1 10001111 0f 110001 ^1101%0 01100^1 01101011 %
LI 10001111 0T 110001
® 10000011 00001100
LI 11101111 11011111
LI 00000001 10000111
1001j^lll
10001111
10001111 y
10001110
000101211
11110000
11111000
00000101
10001010
10li2ll010
11010101
00101011
10001111
11100000
10001110
00011111
10001010.
10000111
00011110
10101011
10001101
10001110
00011100
11010101
10101010
10001010
01010010
00010101
01110101
10/01000
10000000
10001111
10001111
00101010
'01101T00
01000011
10111 Lll
01010100
1015^1110
10000111
10000111
10001111
00010101
00011100
10101010
11111000
01010100
10101110
11100011
10001010
10001101
11000000
10000011
00011111
10001010
01000011 10000011 1S2
11111101 11111110 IJ^
10001111 00001111 ly
10001111 00010111 0j2
10001111 10101011 0;^
10111111 10010101 01
01001(^10 10000J01 1^
10000011 00000111 00
11100011 10001110 111
IQiK/jl/M l|Wl(^lJ2f 1)^
IIAYI3KX ^000101 1)^
fcSTlZJTTOZ^ Wi010100 0^
10000011 00010101 i;i
00101000 11000101 lO;
11100010 10001010 00
11100011
11100000
00001111
01010000
10001010
10101000
10000000
01111110
10000111
10001111
Digitized by the Internet Archive
in 2014
https://archive.org/details/z808080assemblyl00kath
Z-80 and 8080
Assembly Language
Programming
Hayden Computer Programming Series
BASICS OF DIGITAL COMPUTER PROGRAMMING (Second Ed.)
John S. Murphy
BASIC BASIC: An Introduction to Computer Programming in BASIC Language (Second Ed.)
James S. Coan
ADVANCED BASIC: Applications and Problems
James S. Coan
DISCOVERING BASIC: A Problem Solving Approach
Robert E. Smith
PROGRAMMING PROVERBS
Henry F. Ledgard
PROGRAMMING PROVERBS FOR FORTRAN PROGRAMMERS
Henry F. Ledgard
FORTRAN WITH STYLE: Programming Proverbs
Henry F. Ledgard and Louis J. Ciimura
COBOL WITH STYLE: Programming Proverbs
Louis J. Chmura and Henry F. Ledgard
BASIC WITH STYLE: Programming Proverbs
Paul A. Nagin and Henry F. Ledgard
PASCAL WITH STYLE: Programming Proverbs
Henry F. Ledgard and Paul A. Nagin
FORTRAN FUNDAMENTALS: A Short Course
Jack Stelngraber
THE BASIC WORKBOOK: Creative Techniques for Beginning Programmers
Kenneth E. Schoman, Jr.
BASIC FROM THE GROUND UP
David E. Simon
APL: AN INTRODUCTION
Howard A. Peelie
Z-80 AND 8080 ASSEMBLY LANGUAGE PROGRAMMING
Kathe Spracl<len
1
Z-80 and 8080
Assembly Language
Programming
KATHE SPRACKLEN
HAYDEN BOOK COMPANY. INC.
Rochelle Park, New Jersey
To my precious stepdaughters
Teresa and Amy
ISBN 0-8104-5167-0
Library of Congress Catalog Card Number 79-65355
Copyright © 1979 by HAYDEN BOOK COMPANY, INC. All rights reserved.
No part of this book may be reprinted, or reproduced, or utilized In any
form or by any electronic, mechanical, or other means, now known or
hereafter invented, including photocopying and recording, or in any infor-
mation storage and retrieval system, without permission in writing from
the Publisher.
Printed in the United States of America
123456789 PRINTING
79 BO 81 82 83 84 85 86 87 YEAR
Preface
My first concern was chess. The dream was and is to create a microcom-
puter program that can play chess at the master level. But computer chess
could not be done effectively using BASIC. It had to be assembly language.
For Dan and me learning and using Z-80 assembly language posed no prob-
lem because of our prior background writing in other assembly level lan-
guages. But we wanted also to share what we had done in creating SARGON,
and for many potentially gifted programmers there seemed to be a desperate
lack of suitable introductory material. I was especially concerned with texts
that insult the intelligence of the reader. Yet among those written for the
capable layman there seemed to be a heavy emphasis on the hardware aspects
of microprocessors. What I wanted to see was a book that taught Z-80 assem-
bly language as a first assembly language; a book that emphasized software
and covered the xises of the machine instructions in tackling a programming
project. This book was written to fill that need.
In creating this book I owe a double debt to Professor David Solomon,
San Diego State University. Dr. Solomon provided me with my first introduc-
tion to assembly language and later to microcomputers. In his classes I en-
joyed the delicious dawning of understanding of just what a computer is and
does. I thank my students at The Computer Center, Ronson Rd., San Diego,
for their comments and suggestions on the first draft of this book, particularly
Arthur Wolman. To my husband, Dan, go many thanks for giving me the
computer "bug" in the first place and for leading the way in computer chess.
Finally I would like to thank my mother, Margaret Shannon, and my grand-
mother, Julia Dumas, for providing two generations of creative, competent
women to admire and emulate.
Kathe Spracklen
San Diego
Contents
Introduction 1
Bits, Bytes, and Boolean Operators 4
Where Is My Variable? 14
A Method to Our Logic 31
Jumps, Loops, and Modular Programming 43
Bit Fiddling and Message Making 57
A Casual Introduction to Data Structures 71
Binary Coded Decimal Arithmetic 83
When Time Is Important 96
Appendix A: 8080/Z-80 Conversion Chart
and Instruction Summary 103
Appendix B: ASCII Code Summary 113
Appendix C: 8080 Disassembler 114
Appendix D: Z-80 Extension Disassembler 119
Appendix E: Answers to Exercises 125
Index 166
I
introduction
Are you bored with BASIC?
Do your photon torpedoes drift listlessly across your screen?
Does it take ages to age your accounts receivable?
Maybe you're ready to tackle assembly language programming. If so, this is
the place to start. This book assumes that you know a little bit about com-
puters and have done some programming in a higher level language like
BASIC or FORTRAN. It assumes familiarity with words like
VARIABLE
GOTO
LOOP
ARRAY
The approach is designed for the novice to assembly programming and is
intended to provide just about everything the applications programmer needs
to know to get the most out of his machine. Some topics are conspicuously
omitted, since they are really relevant only to someone designing a monitor
program or operating system. The emphasis here is to give the user all the
information needed to interact with his monitor.
Here are some of the features that make this book unique.
• Each concept and instruction is carefully explained.
• Numerous diagrams and examples are provided.
• Exercises designed to instruct and challenge you are included with each
chapter, and answers to each are provided.
• Programming techniques are presented along with the instructions.
There are eight chapters in this book. Each chapter gradually builds on the
work of preceding ones. The exercises are a part of the instructional material
as well. Do try them. They will help you quickly develop your skills as an
assembly language programmer, as most exercises ask you to write segments
of code. When you turn to the answers, however, please remember that what
you see is but one possible way of doing things. It is very unlikely that we will
1
2
Z-8B and 8B8B Assembly Language Programming
agree totally on the approach to take, so to check your work try it out on your
computer.
Assembly programming is really worth the effort it takes when you're
new at it. Later, when you become comfortable with the instructions, it is
only slightly more difficult than BASIC. In return it gives you
• complete control of your system
• flexibility in the management of your data
• speedier execution
• compact programs
Then, too, there's that delicious sense of satisfaction when you can say: "No,
it's not in BASIC. I wrote it in assembly language."
The programs we will write in assembly language are much different
than programs written in BASIC. Each line of a BASIC program is translated
by another program (called a BASIC interpreter) into several lines of assem-
bly level code. An example will serve to illustrate this one-to-many transla-
tion. Suppose we write an algebraic statement in BASIC: Z = X + Y. Let's
see the assembly level statements that could be used to accomplish this.
1. Go get the value of X and place it in the accumulator. (The ac-
cumulator is the spot where the addition will take place.)
2. Set up a pointer to the location where the value of Y is stored.
3. Add the accumulator contents to the value the pointer locates. (The
sum will be left in the accumulator.)
4. Store the contents of the accumulator in the location belonging to Z.
The assembly level statements are the closest to the actual computer actions
that a programmer may specify. Each statement written in assembly language
is translated by another program (called an assembler) into one machine
instruction.
All machine instructions are strings of 0s and Is. One example is
10111000
Now this may make perfect sense to a computer, but humans tend to think
better in words. This is where assembly language comes in. It allows the
programmer to refer to the instructions in word- like abbreviations called
mnemonics.
In this text we will be studying most of the instructions available to the
programmer of the Z-80 microprocessor. In each case we will learn
1 . how the instruction works
2 . the mnemonic
3. the machine code (OP code)
Introduction
3
The job of the assembly language programmer is to know how the in-
structions can do the job he needs done and to write the instruction
mnemonics. The job of the assembler program is to translate the mnemonics
into machine code. The job of the computer is to execute the machine code
instructions. Two other programs may be involved in this process. A text
editor program is usually used to write the mnemonics into a text file, usually
maintained on a tape or disk system. A load program (or loader) is used to
input the machine code (often called an object file) into the computer's
memory for execution. The whole process can be summarized as follows.
Programmer
designs program and
writes mnemonics.
Programmer keys
mnemonics in using
text editor program.
He creates a text file
in computer memory or
on tape or disk.
Assembler program
translates mnemonics into
machine code and creates
an object file in computer
memory or on tape or disk.
Loader program brings Programmer runs
object file into program for testing
computer for execution. and debugging.
The emphasis in this text is on the steps of design and coding. Running
the text editor, assembler, and loader is just a matter of following the specific
instructions included with the particular versions running on your system.
Some specific help on how to debug your programs can be found in the final
chapter of this book.
bits, bytes, and
boolean operators
Binary and Hexadecimal Number Systems
The binary number system is the basis of computer operations. It requires the
use of only two digits: 0 and 1. These two possibiHties can be easily
represented by a low and high voltage, respectively. The decimal numbers 0
through 5 appear below written in binary form.
0 = 0
1 = 1
10 = 2
11 = 3
100 = 4
101 = 5
It can be seen that the numbers rapidly become very long.
In the decimal system each digit represents a power of 10. For example
423 = 4 X 100 = 4 X 102
+ 2 X 10 + 2 X 10'
+ 3x1 + 3 X 100
(Any number raised to the 0 power is 1 . So, 2" = 1 , 10" = 1 , and 16" = 1 .)
In the binary system, each digit represents a power of 2.
1101 = 1 X 2' = 1x8
+ 1 X 22 +1x4
+ 0x2^ +0x2
+ 1x2" +1x1
So 1101 in binary is the equivalent of 13 in decimal. Conversion between the
two number systems can be done using these rules, but it is not common to
have to convert numbers larger than 15 back and forth. Larger numbers are
generally first converted into the hexadecimal system.
In the hexadecimal, or base 16, number system, there are 16 different
digits. The digits 0-9 are borrowed from the decimal system, and letters of
the alphabet fill in for the other six.
4
Bits, Bytes, and Boolean Operators
5
A =
10
B =
11
C =
12
D =
13
E =
14
F =
15
In the hexadecimal system, each digit represents a power of 16.
1B3 = 1 X 162 = IX 256
+ B X 16' + 11 X 16
+ 3 X 16" +3x1
So 1B3 (hexadecimal) is the equivalent of 435 in the decimal system.
With three number systems in use, some way to distinguish between them
is necessary. Whenever confusion could arise, we will use a subscripted letter
to distinguish between the systems.
10j^ — Hexadecimal
10Q — Decimal
10g — Binary
Converting Between the Systems
Conversions of small numbers can be done using the following chart.
Decimal Binary Hexadecimal
0 0 0
1 1 1
2 10 2
3 113
4 100 4
5 101 5
6 110 6
7 111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
16 10000 10
6
Z-80 and 8080 Assembly Language Programming
Hexadecimal-Decimal
Hexadecimal numbers can be converted into the decimal system most easily
by using the powers of 16. The following example shows how to convert
2AF3jj to decimal.
2 X 16» = 2 X 4096 = 8192 = 10,995^,
+ A X 16* + 10 X 256 + 2560
+ F'x 16° + 15 X 16 + 240
+ 3xl6» +3x1 +3
Conversions from decimal to hexadecimal can be done using division and
the following chart of powers of 1 6 .
Powers of 1 6
16« = 1
16> = 16
162 = 256
16^ = 4,096
16* = 65,536
Numbers larger than 16* are rarely encountered. We will always begin by
dividing by the largest power of 16 that will fit. Beginning with 10,995jj,
here's how to get back to 2AF3j^.
2 r 2803
4096 I 10,995
10 r 243
256 I 2803
15r 3
16 I 243
3
1 IT" 3
Hexadecimal- Binary
Conversions between hexadecimal and binary are extremely easy. Every
hexadecimal digit can be translated into four binary digits using the con-
version chart. For example,
53Dh = 101 0011 1101b
Binary numbers can be converted to hexadecimal by counting off groups
of four digits beginning from the right. Then each group is translated into a
hexadecimal digit. Thus,
Bits, Bytes, and Boolean Operators
1011101101b = 10 1101b =2EDh
Bits and Bytes
A bit is the unit of storage required to hold one binary digit. We will denote a
bit by enclosing the 0 or 1 value in a box as shown.
m
0
or
Sometimes bits are important in themselves, but usually they are con-
sidered in groups. A group of eight bits is called a byte. We v^ll denote a
byte as a string of eight boxes.
0 10 0 10
1
Since four bits make one hexadecimal digit, it takes two hexadecimal digits to
describe the contents of a byte. Sometimes a group of four bits is called a
nibble.
The byte is the basic arithmetic unit of a microcomputer. If we only want
to count, the highest number we can count to in a byte is 255.
1
1
1
1
1
1
1
1
= FF.
255.
We also have the capability of adding two positive numbers, so long as they do
not total more than 255. But how can we subtract? Subtraction requires the
ability to express negative numbers.
2's Complement Representation
We would like to have the ability to represent negative as well as positive
numbers. This is accomplished by reserving one of the eight bits as an in-
dicator of the sign of the number.
x
x
X
X
X
X
X
I X
x
X
X
X
X
X
Positive (0 sign bit)
Negative (1 sign bit)
By tying up one of the eight bits to indicate the sign, we are left with only
seven bits for the magnitude of the number. So the highest number we can
count to is 127.
0
1
1
1111
1
So how would we represent - 127? A first try might be to simply reverse the
sign bit and leave all the magnitude bits unchanged. Although this scheme is
easy to understand, it turns out to be very difficult to work with.
A second try might be to reverse all the bits. This is called I's com-
plement.
8
Z-80 and 8080 Assembly Language Programming
0
0
0
1 1
0
0
1
1 1
0
0
1
0
1
= 26
D
= I's complement of 26
If we used this method to represent negative numbers, let's see where it would
lead. We would certainly want 26 and - 26 to add up to zero. But
+
0
0 0
1
1
0
1
0
1
1 1
0
0
1
0
1
11111
1 1
1
when we'd really like all 0s. However, if we add 1 and ignore the carry, we get
just what we want:
1
1
1
1
1
1
1
+ |0
0
0
0
0
0 1
carry
|0
0
0
0
0
0
0
Out of this reasoning came 2's complement representation of negative
numbers. 2's complement is formed by adding 1 to the I's complement form.
+
0
0
0
1
1
0
1
0
= 26^
1
1
1
0
0
1 0
1
= I's complement of 26
0
0 0
0
0
0
0
1
1
1
1
0
0
1
1
0
0 = 2's complement of 26
Converting a negative number back to positive can be done using the exact
same steps.
1
1
1
0
0
1
1
0
0
0
0
1
1 0
0 1
0
0
0
0
0
0
0
1
0
0
0
1
1
0
1
0
= -27,
= I's complement of — 26
= 26
D
Byte-Size Arithmetic
We are now equipped to perform addition and subtraction of binary num-
bers. Here are some examples.
Bits, Bytes, and Boolean Operators
11
0
0
0
0
1
0 1
1
11
0
0
0
0
1
0|l
1
+ 7+00
0
0
0
1 1
1
-7
0
0
0
0
0
1
1
1
18
0
0
0 1
0
0
1 0
4
0
0
0
0
0
1
0
0
Arithmetic Flags
We have already seen one of the arithmetic flags, the carry flag. It is set
whenever the result of an addition is larger than eight bits.
1
0
0
0
0
0
0
0
1
+ (-1) +
1
1
1
1
1
1
1
0 carry [Tl
0
0
0
0 0
0
0
0
In addition the carry bit is most often just ignored. It is simply a by-product of
2's complement representation.
In subtraction the carry bit has more meaning.
1 carry [T| 1 0
0
0
0
0
0
0
1
2 - 0
0
0
0
0
0 1
0
1 1
1
1
1
1 1
1
1
Here it is when a borrow is generated. Thus the carry bit tells us that we
subtracted a number from a smaller number.
The overflow flag is an indication that something's gone wrong. We
know that an eight bit number with one sign bit and seven magnitude bits
cannot be larger than 127. The smallest it can be is — 128.
1
0000000 =- 128
Now suppose we try to add 75 and 80:
75
0 10 0 10
+ 80
+ 0 10 1 0 0 0 0
155
0 0
0
10
Z-Sdand 8080 Assembly Language Programming
What has happened is that the magnitude bits have carried over into the sign
bit, making the result look like a negative number. The overflow flag is then
set to indicate that the answer is unreliable. This can also happen when two
large negative numbers are added. The overflow flag is again set to point up
the trouble.
(-75)
10 110 10 1
+ (-80) +
I— (
0
1
1
0
0
0
0
-155 [T|
0
1
1
0
0 1
0 1
Again the sign bit was reversed. The carry flag was also set, but that is
unimportant.
If the two operands to be added are of opposite sign, no overflow can
occur.
Two other flags are very simple in their operation. The sign flag in-
dicates whether the result of an arithmetic operation is positive or negative. It
is an exact copy of the sign bit, so 0 means the result was positive and 1 in-
dicates a negative result. Since a zero result has a 0 sign bit, it is obviously
considered to be a positive number. A zero result, however, is so important
that it is reported in a flag all its own. The zero flag is set when the result is
zero.
Summary of Eight Bit Arithmetic Flags
Carry (C) — Carry out of the eight bits
1 : occurred
0: did not occur
Overflow (V) — Sign bit clobbered
1 : occurred
0: did not occur
Sign (S) — Result was
1 : negative
0: positive
Zero (Z) — Zero result
1 : occurred
0: did not occur
Bits, Bytes, and Boolean Operators
11
Boolean Operators
Arithmetic is not the only thing that can be done to pairs of eight bit values.
There is the whole class of logical, or Boolean, operators. Boolean operators
treat all eight bits alike, with no sign bit.
AND
The AND operator compares two bytes bit by bit. If a bit is set in both
operands, it is set to 1 in the result. Otherwise the bit is reset to 0 in the result.
This operation is summarized in the following table.
ABA AND B
1 1 1
1 0 0
0 1 0
0 0 0
Usirg this table, each of the bits in a byte is set or reset in turn, as in the
following example.
1
1
0
0
0
0
1
1
AND
1
0
1
0
0
1
0
1
A
B
1
0
0
0
0
0 0 1
OR
The OR operator compares two bytes bit by bit. If a bit is set in either
operand, it is set in the result. Otherwise it is reset in the result.
A
B
A ORB
1
1
1
1
0
1
0
1
1
0
0
0
1
1
0
0
0
0
1 1
A
OR
1
0 10 0 10 1
B
1 1
1
0
0
1 1 1
A ORB
12
Z-80and 8680 Assembly Language Programming
XOR
The XOR (exclusive OR) operator compares the two bytes bit by bit. If the
bit is set in either operand, but not in both, it is set in the result. Otherwise it
is reset in the result.
A B AXORB
1
1
0
0
1
0
0
1
1
1
0
0
1
1
0
0
0
0
1
1
XOR 10 10 0 1
A
B
0
1
1
0
0
1
1 0
0 A XOR B
Flags and the Binary Operators
Carry - Reset by AND, OR, and XOR
Zero — Indicates that all bits of the result are zero
1 : occurred
0: did not occur
Sign — Set to the value in the uppermost bit (same as
arithmetic operation)
Logical operations affect the parity flag instead of the overflow flag. The
parity flag tells whether an even or an odd number of bits are set in the result.
The parity flag is set when an even number of bits are set in the result. The
flag is reset when an odd number of bits are set in the result.
Result
Result
0
0 1 0
P = 0
0 0 0 0 0 0
P = 1
(five bits set)
(two bits set)
Exercises
1 . Convert the following numbers to decimal.
a. 101 e. 10000000
b. 1101 f. 11001010
c. 11101 g. 10001110
101011
11111001
i. 00010010
j. 01110011
k. 111000100
1. 1010101011
1
Bits, Bytes, and Boolean Operators
13
2. Convert the following decimal numbers to hexadecimal and then from
hexadecimal to binary.
a. 6 e. 542 i. 15,430
b. 14 f. 1077 j. 43,751
c. 127 g. 4095 k. 65,552
d. 280 h. 8702 1. 70,980
3. Give the eight-bit signed representation of the following positive numbers.
Then convert each to 2's complement.
a. 7 c. 23 e. 104
b. 17 d. 48 f. 127
4. Given the following bytes with one sign bit and seven magnitude bits, give the
decimal equivalent of their contents.
a. 0
0
0 0
1
0
0
1
d.
0
0
1
0
0
1
1
1
b.
0 0 0 1 1 0 0
110 0 10
c.
1
1
1
1
1
0
1
1
f.
1
1
0 1
0
0
0
0
5. Perform the following arithmetic operations in binary form. For each, give
the result in binary, and tell whether the carry and/ or overflow flags are set.
a. 11 + 15 d. 104 + 55
b. 17 + (-21) e. (-67) - 107
c. 46-12 f. (-67) + 107
6. For each of the following pairs of bytes, find their AND, OR, and XOR.
Indicate what flags are set.
0
0
0
0
0
0
0
0
0 0
0 10 0
0
0
0 1 0
0
0 0
0
b.
1
1
1
1
1
1 1
1
f.
1
0
0
0
0
0
0
0
1 0
1 1
0
1
0
0
0
1
1 1 0
0 0
1
1
1
0
1
1
1
1
1
0
0
1
1
0
1
1
0
0
1
0
1
0
1 0
1
1
0
1
0
1
0 1
0
d.
1
1
1
1
0
1
1
1
h. 1
1
0
0
1
1
1
1
1
0
1
0
0
0
1
0
1
1
0
0
1
1
1
1
where is my variable?
The Higher Level Language Programmer
Whatever else the higher level language programmer may know about his
program, he probably has very little sense of where his variables are located.
Consider the following program:
X = 3
Y = 2
Z = X + Y
PRINT Z
Where is X? Where is Y? Where does the addition take place? The whole
"where" aspect is generally quite foreign to the new assembly language
programmer. Also missing is the language needed to talk about "where"
topics.
Registers
The registers are one of the most common answers to a "where" question.
Here is a diagram of the 8080 register set. (The Z-80 has these and more.)
A
Flags
B
C
D
E
H
L
Each of the registers is eight bits long. The bits are numbered from right to
left. All of the registers look alike. Here is a close-up of one of the registers.
Bit# 76543210
1
0
1
0 10 10 Register E
The A register is the answer to the question: "Where does the addition
take place?" Also called the accimiulator, register A always holds one of the
two operands in an add, subtract, AND, OR, or XOR operation. The result
14
Where Is My Variable?
15
is also left in register A. So every arithmetic and logical operation is of the
form
X-^X A Y
The register labeled "Flags" is where the carry, overflow, and other flag bits
are stored. It is usually accessed only one bit at a time.
Registers B and C, D and E, and H and L may be treated as register
pairs. Then the two eight bit registers may instead be regarded as one 16 bit
register. Besides being able to house a larger number, the main use of 16 bit
values in a microcomputer is to address memory.
Memory
Memory is the most likely answer to the question concerning the whereabouts
of any variable. It also answers the question "Where is my program?"
Memory is divided into individual bytes. Each byte in memory has a
unique address. Addresses in the 8080 and Z-80 are all two bytes in length.
How much memory can be addressed in two bytes? Consider the following
progression.
# of Bits
Size of Memory
Highest Address
in Hexadecimal
8
256 bytes (0-255)
FF
9
512 bytes
IFF
10
1024 bytes = Ik
3FF
11
2048 bytes = 2k
7FF
12
4096 bytes = 4k
FFF
13
8192 bytes = 8k
IFFF
14
16,384 bytes = 16k
3FFF
15
32,768 bytes = 32k
7 FFF
16
65,536 bytes = 64k
FFFF
One byte addresses only allow for Y^k of memory. Since this is usually
inadequate, the logical choice was to go to two bytes for an address. A two
byte address allows the possibility of addressing 64k of memory.
We have already mentioned that the BC, DE, and HL register pairs may
be used to contain memory addresses. There are, in addition, two other 16
bit memory address registers common to the 8080 and Z-80 microprocessors.
Stack Pointer and Program Counter
The stack pointer (SP) is a 16 bit register whose only function is to point to a
location in memory.
16 Z-80 and 8080 Assembly Language Programming
3C04
In the Z-80 microprocessor, the stack is just a designated portion of regular
memory. The programmer sets the stack to the location of his choosing. With
the question "Where is the stack?" out of the way, a good question to consider
next is "What is the stack?"
A stack, in the general sense, is a collection of items where all additions
and all deletions occur at the top. A stack of dishes, for example, fits this
description.
The stack Addition to Deletion from
the stack the stack
The characteristic of a stack is that only the top is accessible.
The stack in the Z-80 or 8080 sense is a region of memory where values
can be saved temporarily. Its most common use comes in relation to
subroutine calls, but it can be used to store intermediate results in a com-
putation, or any short-lived variable. Use of the stack for these purposes saves
having to use a separate, unique memory location for transient data.
The program counter is also a 16 bit register which points to an address
in memory. That address is located within the program that is currently
running, and contains the next instruction to be executed.
r
Where Is My Variable?
17
Notation
Suppose we have a variable located in memory which we have called VAR-
BLE. Since VARBLE is located in memory, it has an address. It also has a
value. So when we use VARBLE, which do we mean, the address or the value?
To the higher level language programmer there can be no problem. He knows
nothing of the whereabouts of his variables. When he uses VARBLE he
means its value.
The assembly language programmer will deal with both values and
addresses. It is the instructions themselves which will clarify the usage. Some
instructions operate on values, others deal with addresses. But to talk about
the instructions requires a new notation. In this context, n will denote an
eight bit number, and nn a 16 bit number. So we will use
nn as the address, and
(nn) as the value
Mnemonics
To the microprocessor, an instruction is a bit pattern called an OP code. The
binary values are most often written in hexadecimal. To the human, a bunch
of numbers, hexadecimal or binary, are difficult to relate to. Mnemonics are
short, word-like abbreviations for the instructions which are translated into
their numeric equivalents by a program called an assembler.
For each of the instructions we will be studying the hexadecimal OP code
and mnemonic will be given. Mnemonics for the 8080 and Z-80 are not the
same even though the OP code and instruction execution are. So both
mnemonics will be given. In addition, note that the TDL Z-80 assembler uses
8080 mnemonics.
Eight Bit Load Instructions
Register- Register
The contents of any eight bit register can be moved to any other eight bit
register.
MOV E,A (8080)
LD E.A (Z-80)
The contents of register A would then be moved into register E (to E from A).
The target is listed first. This class of load instructions is denoted
MOV r.r' (8080)
LD r.r' (Z-80)
18
Z-80 and 8080 Assembly Language Programming
where r and r ' can be any of A, B, C, D, E, H, and L, and the action is r-«-
r'.
The OP code for our sample instruction (E A) is 5Fj^. Here is a chart
which gives the OP codes for all register- register moves.
Register
Source Register
A
B
C
D
E
H
L
A
7F
78
79
7A
7B
7C
7D
B
47
40
41
42
43
44
45
C
4F
48
49
4A
4B
4C
4D
D
57
50
51
52
53
54
55
E
5F
58
59
5A
5B
5C
5D
H
67
60
61
62
63
64
65
L
6F
68
69
6A
6B
6C
6D
Register-Memory
Eight bit values can be loaded from memory into the registers and from the
registers to memory. Movements between the accumulator (register A) and
memory can be accomplished in several different ways. Movements between
memory and any other register are very restricted.
We mentioned that the register pairs BC, DE, and HL can be used as
pointers to memory. The HL pair is by far the most commonly used for this
purpose. Suppose we have the following situation.
AF
BC
DE
HL
28
7B
04
287A
287B
287C
287D
287E
The HL register points to memory location 287B which contains the value
04p^. This value can be loaded into any of the eight bit registers using the
instruction
MOV r,m (8080)
LD r,(HL) (Z-80)
I
Where Is My Variable?
19
In the 8080 mnemonic, M indicates a memory reference and always refers to
the memory location pointed to by the HL pair.
In this instruction, the movement can be depicted as
r^(HL)
Movement in the opposite direction is also possible:
(HL)^r
Here the contents of any eight bit register can be stored in the memory
location pointed to by the HL pair. The instructions are
MOV M,r (8080)
LD (HL),r (Z-80)
Both of these instructions have separate OP codes for each eight bit register.
The OP codes are summarized in the following table.
A
B
C
D
E
H
L
r ^ (HL)
7E
46
4E
56
5E
66
6E
(HL)^ r
77
70
71
72
73
74
75
Register A -Memory
Additional movements between the accumulator and memory are possible.
Four of them are just like the register-memory (HL) instructions just
described. They are summarized in the following table.
Action OP Code 8080 Mnemonic Z-80 Mnemonic
A-^(BC) 0A LDAX B LD A, (BC)
A-^(DE) lA LDAX D LD A, (DE)
(BC)-^A 02 STAX B LD (BC), A
(DE)-^A 12 STAX D LD (DE), A
Missing so far in all these register- memory movements is the ability to
load the value of a variable by name. That is,
A-»-(VARBLE)
or
(VARBLE)-^ A
Both of these actions are possible, but more information than just the OP
code is required. Besides telling the computer we want to load a variable from
memory, we have to tell it which one.
Before, when we wanted to load a location from memory, we answered the
question "Which one?" with "The one pointed to by the HL (or BC, or DE)
20
Z- 80 and 8080 Assembly Language Programming
pair." So the location didn't have to be contained in the instruction. This time
we will have to give the location.
LDA VARBLE (8080)
LD A, (VARBLE) (Z-80)
We give the assembler the name of the variable. The assembler translates the
name into its two byte address. (It keeps a symbol table for this purpose.)
Suppose VARBLE is stored at location 23F3. Then this address would
become part of the instruction. One byte would be used for the OP code and
two for the address, so the whole instruction would be three bytes long. Here
are the possibilities (nn stands for the variable name in the mnemonic and for
its address in the instruction).
Operation OP Code 8080 Mnemonic Z-80 Mnemonic
A-»-(nn) 3 Ann LDA nn LDA,(nn)
(nn)— A 32nn STA nn LD(nn), A
Register-Immediate
Suppose we want to place a certain value into a register or memory location.
A—?
The number 7 is an absolute value, or an immediate. We can store any eight
bit absolute value into any of the eight bit registers or into the memory
location pointed to by the HL register pair.
The absolute value desired is written with the mnemonic and is
assembled directly into the instruction. The instruction then becomes two
bytes long.
MVI C,-27 (8080)
LD C,-27 (Z-80)
After executing this instruction, register C would then contain
( — 27 in 2's complement form)
1 1
1
0 0
1
0
1— >
The possibilities are charted below. The letter n stands for the eight bit
absolute value.
Operation 8080 Mnemonic Z-80 Mnemonic
r-^n MVI r,n LD r,n
(HL)<^n MVI M,n LD (HL),n
The OP codes for the immediate instructions are presented in the following
table.
Where Is My Variable?
21
A
B
C
D
E
H
L
(HL)
3En
06n
0En
16n
lEn
26n
2En
36n
Here s stands for r or (HL) and n is in 2's complement form if negative.
Z-80 Indexed Eight Bit load and Store
Two other 16 bit registers exist in the Z-80 microprocessor. These are the IX
and lY index registers.
IX
lY
Like the stack pointer and program counter, these registers are used exclu-
sively to point to memory locations. Like the HL pair, they are generally used
to point to variables in memory.
The index registers can, hov^ever, be used with a displacement. A
displacement is an eight bit signed number which is coded directly into the
instruction. Here is an illustration of how the index registers work.
IX 3 4 4 3 n
\ IX
1 ir
0 0
\
I
d: 05
IX+d
'- ^
•
•
•
F F
3443 (IX)
3448 (IX+d)
In this illustration the IX index register points to memory location 3443^^.
The value of the displacement is 05j_,. So the location that would be affected
by the instruction would be 3443^ + 05^^ = 3448^^. Take for example the
following load instruction into the B register.
MOV B,5(X) (TDLZ-80)
LD B,(IX + 5) (Z-80)
At the conclusion of the operation register B would contain FF^^, not 00.
The displacement is a signed eight bit number. So its values can range
from - 128 to -H 127.
Indexed instructions can be tricky to deal with, and much will be said
later about techniques for using them.
22
Z-86and 8080 Assembly Language Programming
Diagramatically, the load and store index instructions fall into one of
three categories. Here ii will mean the IX or lY index register. Note that an
immediate can be loaded into an indexed memory location.
r^(ii + d)
(ii + d)-^ r
(ii + d) n
Since the displacement is coded into the instruction, the instruction must
be at least two bytes long. In fact, it is three bytes long. Two bytes are used for
the OP code. Most of the Z-80 instructions which are extensions of the 8080
instruction set are two bytes long. All of the IX index OP codes begin with DD
and the lY with FD. Index instructions which include an immediate are four
bytes long.
Here, then, are the OP codes for the Z-80 index instructions.
A
B
C
D
E
H
L
r ^ (IX+d)
DD7Ed
DD46d
DD4Ed
DD56d
DD5Ed
DD66d
DD6Ed
r <^ (lY+d)
FD7Ed
FD46d
FD4Ed
FD56d
FD5Ed
FD66d
FD6Ed
(IX+d)^r
DD77d
DD70d
DD71d
DD72d
DD73d
DD74d
DD75d
(lY+d)
FD77d
FD70d
FD71d
FD72d
FD73d
FD74d
FD75d
(IX+d)— n DD36dn
(IY+d)-^n FD36dn
16 Bit Load and Store Instructions
Register Summary
Before going further, let's take a moment to review the registers discussed so
far:
8080 Registers
' AF
BC
DE
HL
IX
lY
SP
PC
AF
BC
DE
HL
SP
stack pointer
PC
program counter
Register- Register
We saw
that it was
possible to
Z-80 Re
gisters
stack pointer
program counter
any other eight bit register. Movements between 16 bit registers are, by
Where Is My Variable?
23
contrast, almost nonexistent. Only the stack pointer (SP) can receive a value
from another 16 bit register. Even then, there are only three possibilities.
TDLZ-80 &
Action OP Code 8080 Mnemonic Z-80 Mnemonic
SP— HL F9 SPHL LDSP,HL
SP-i-IX* DDF9 SPIX LDSP.IX
SP^jY* FDF9 SPIY LDSP.IY
*Z-80 only.
Memory- Register
In the eight bit load instructions it was possible to load and store values from
memory locations pointed to by the HL pair, r-«-(HL). This does not occur
for 16 bit registers at all. We also saw that the contents of a one byte variable
could be loaded into the accumulator by referencing its name. A two byte
variable can be loaded or stored in the HL pair by referencing its name.
LHLD BIGVAR (8080)
LD HL, (BIGVAR) (Z-80)
Here, the contents of the address BIGVAR and the address BIGVAR -I- 1 are
loaded into the HL pair.
Swapped Format. A two byte variable is stored in memory in what is
known as swapped format. By this is meant that the low order byte is loaded
at the lower memory address. An example should make this clear. Suppose
BIGVAR is stored at location 1F23.
HL
56
43
(after loading
BIGVAR)
43
56
1F23 BIGVAR
1F24 BIGVAR + 1
Two byte variables are not the only numbers stored in swapped format. If an
8080 or Z-80 instruction contains within it a two byte address, that address is
stored in swapped format. Our example load instruction has OP code 2A and
the address of BIGVAR is contained within the instruction, so the instruction
in hexadecimal would be
2A231F
This ability to load and store a named 16 bit variable exists in 8080 for the HL
register pair only. The Z-80 microprocessor possesses this capability for the
24
Z-80and 8080 Assembly Language Programming
BC, DE, HL, SP, IX, and lY registers. Here are the instructions and OP
codes (nn stands for the two byte address, and rr for the register name).
TDL Z-80 and
Operation OP Code 8080 Mnemonic Z-80 Mnemonic
8080 — (nn) 2Ann LHLD nn LD HL,(nn)
& (nn)-« — HL 22nn SHLD nn LD (nn),HL
Z-80
Z-80
only
BC -^(nn)
ED4Bnn
LBCD nn
LD BC,(nn)
(nn)-*- BC
ED43nn
SBCD nn
LD (nn),BC
DE -^(nn)
ED5Bnn
LDED nn
LD DE,(nn)
(nn)-^ DE
ED53nn
SDED nn
LD (nn),DE
SP -^(nn)
ED7Bnn
LSPD nn
LDSP,(nn)
(nn)-^ SP
ED73nn
SSPD nn
LD (nn),SP
IX ^(nn)
DD2Ann
LIXDnn
LDIX,(nn)
(nn)-^ IX
DD22nn
SIXDnn
LD (nn),IX
lY ^(nn)
FD2Ann
LIYDnn
LD IY,(nn)
(nn)-^ lY
FD22nn
SIYD nn
LD (nn),IY
Register- Immediate
Just as a one byte immediate could be loaded into any eight bit register, so can
a two byte immediate be loaded into any 16 bit (double eight bit) register.
Usually that value is an address.
LXI H.BIGVAR (8080)
LD HL.BIGVBAR (Z-80)
The above instruction has the effect of loading BIGVAR'S address (not its
value) into the HL pair. Diagrammatically,
rr^- nn
A constant can also be loaded using these same instructions.
The 8080 possesses all of these immediate instructions except the two
that reference the IX and lY index registers. The OP codes are given below.
BC
DE
HL
SP
IX
lY
rr-*-nn
01nn
linn
21nn
3 Inn
DD21nn
FD21nn
The mnemonics for these are
LXI rr,nn (8080)
LD rr.nn (Z-80)
Note that the meaning of rr differs for the 8080 and Z-80. The Z-80 uses
any one of BC, DE, HL, SP, IX, or lY. The 8080 uses B for BC, D for DE, H
Where Is My Variable?
25
for HL, and SP for SP. The TDL assembler uses the 8080 form and, in ad-
dition, X for IX and Y for lY.
PUSH and POP Instructions
PUSH and POP instructions transfer values back and forth between register
pairs and the stack. For this purpose the A register and the flag register are
treated as a pair.
In a PUSH instruction, the contents of a registered pair are stored on the
stack, and the stack pointer is adjusted. The stack always grows from high to
low addresses, so to add an item to the stack the stack pointer must be
decremented.
SP —
t
3FFD
3FFE
3FFF
22
53
76
•
•
•
HL
IB
24
The execution of a PUSH action has four distinct phases. Consider the action
of pushing the contents of the HL pair onto the stack:
1 . The stack pointer is decremented.
SP —
22
53
76
3FFC
3FFD
3FFE
3FFF
HL IB
24
2. The high order byte (register H) is stored.
SP
IB
22
53
76
3FFC
3FFD
3FFE
3FFF
HL
IB 24
26
Z-8d and 8086 Assembly Language Programming
3. The Slack pointer is decremented again.
SP —
IB
22
53
76
3FFB
3FFC
3FFD
3FFE
3FFF
HL
IB
24
4. The low order byte (register L) is stored.
SP
3FFB
3FFC
3FFD
3FFE
3FFF
24
IB
22
63
76
•
•
•
The POP instruction is the exact opposite of PUSH. For both the 8080
and Z-80 the mnemonics are the same:
PUSH
POP
rr
rr
Again rr is expressed differently for the two mnemonic versions, as was
previously discussed. Also, the A- Flag register pair is referred to as PSW
(which stands for program status word) in 8080 mnemonics and AF in Z-80
mnemonics. Note that the stack pointer itself cannot be pushed or popped.
The relevant OP codes are
8080 & Z-80
Z-80 only
AF
BC
DE
HL
IX
lY
PUSH
F5
C5
D5
E5
DDE 6
FDE5
POP
Fl
CI
Dl
El
DDEl
FDEl
Exchange Instructions
Elxchange instructions swap register contents, or contents of sets of registers.
The 8080 instruction set includes only two such instructions. The Z-80 has six.
The two common to both perform the followdng actions.
Where Is My Variable?
27
HH -
DE
(SP)
So the contents of the HL register can be exchanged with the contents of the
DE register or with the contents of the top of the stack.
HL — — DE
HL-
DE
02
04
DE
30
07
HL
30
07
HL
02
04
Before
'(SP)
After
HL
DC
EE
SP
04 F0
Before
30
27
04EF
04 F0
04F1
04F2
HL
SP
27 30
04F0
After
EE
DC
Mnemonics and OP codes for these are
Exchange OP Code 8080 Mnemonic
04EF
04 E0
04F1
04F2
Z-80 Mnemonic
HL~-DE EB XCHG EX DE.HL
HL-»-^(SP) E3 XTHL EX (SP),HL
The Z-80 has the capability to exchange either the IX or lY index
register with the top of the stack as welL
Action OP Code TDL Z-80 Mnemonic Z-80 Mnemonic
(SP)— ^IX DDES
(SP)-— ^lY FDE3
XTIX
XTIY
EX (SP),IX
EX (SP),IY
28
Z-80 and 8680 Assembly Language Programming
The two other Z-80 exchange instructions swap sets of registers. Besides all the
Z-80 registers given so far, the Z-80 has a duplicate set of the A and flag
registers, and of registers BC, DE, and HL. Exchange instructions swap either
AF and AF' or BC, DE, HL and BC ', DE ', HL '. The swaps appear as
AF
AF'
BC
DE
HL
BC
DE'
HL'
The prime set cannot be addressed or acted on in any way except to swap with
the current set, which then becomes dormant.
Action
OP Code TDL Z-80 Mnemonic Z-80 Mnemonic
AF-«AF' 08 EXAF EX AF.AF'
BCDEHL-^BCDEHL' D9 EXX EXX
The main purpose for these exchange instructions is to provide a very fast
way of saving contents of all the registers. It is important to note that the only
way to access the saved register is to swap back. No values may be exchanged
directly between the two sets of registers.
Exercises
\. Write a sequence of instructions that will swap the contents of the D and
E registers.
2. What will the B register contain after execution of this instruction? (The - 12
is decimal.)
MVI
LD
B, - 12
B, - 12
(8080)
(Z-80)
3. Suppose the HL pair and the given memory locations contain the values
illustrated below.
HL
20
3D
42
F3
39
27
2039
203A
203B
203C
203D
203E
Where Is My Variable?
29
What will register A contain after the following sequence of instructions?
8080 Z-80
MOV L,M LD L, (HL)
MOVA.M LDA,(HL)
4. Using swapped format, give the hexadecimal instruction that loads the value
of M YVAR (address = 34F3) into the A register.
5. Give the effect of
MOV E,12(X) (TDLZ-80)
LD E,(IX+12) (Z-80)
6. Explain the difference between the following pair of instructions.
8080 Z-80
LHLD SPOT
LXI H.SPOT
7. Given the initial register contents
AF: 0402
BC: 4020
LD HL(SPOT)
LD HL.SPOT
H
H
what will these registers contain after the following sequence of instructions?
8080 Z-80
PUSH PSW
PUSH B
POP PSW
POP B
PUSH AF
PUSH BC
POP AF
POP BC
8. Would you expect to get the same number back if you tried this sequence of
instructions?
8080 Z-80
PUSHH
SPHL
POP H
9. Given the memory locations
PUSH HL
LD SP.HL
POP HL
02
03
04
05
6F32
6F33
6F34
6F35
30
Z-80and 8680 Assembly Language Programming
a. What instruction will set the stack to 6F32?
b. What will register pair BC and the stack pointer contain after execution of
the following instruction?
POPB (8080)
POP BC (Z-80)
What does the Z-80 register C contain after execution of the following se-
quence of instructions?
TDLZ-80 Z-80
MVI A, 3
STA SPOT
LIXDSPOT
MOV C,-5(X)
SPOT
21
22
23
24
25
26
LD A. 3
LD (SPOT), A
LD IX, (SPOT)
LD C,(IX-5)
23 FE
23FF
2400
2401
2402
2403
a method to our logic
In the first chapter we discussed the form used to store numbers in the
microprocessor, the method by which addition and subtraction are per-
formed, and the actions of various logical operators. Now we must discuss the
actual instructions which direct these operations. Like the load instructions,
we will have two main groups: eight bit and 16 bit instructions.
Eight Bit Arithmetic and Logical Instructions
The accumulator (register A) is the center of activity for most of the eight bit
arithmetic and logical instructions. In any two-operand instruction, one of
the operands will always be located in the A register. The other operand will
always be contained in one of the registers listed below.
8080 Source Z-80
r Any eight bit register r
M The memory location pointed (HL)
to by the HL pair
n An immediate (eight bit n
absolute value)
d(X)* An indexed memory location (IX + d)
d(Y)* (lY + d)
•TDLZ-80.
We will refer to any one of these collectively with the letter s.
A^ A + s
will describe adding any one of these locations to the accumulator. The 8080
version provides a separate mnemonic for use when one of the operands is an
immediate.
It will be extremely important to consider the effect on the flags of each
of these operations, since the flags provide the programmer with the means of
monitoring the run-time execution of his program. The flags pertinent to our
work now are
31
32
Z-80and 8680 Assembly Langicage Programming
C: Set on a carry out of the register.
Reset otherwise.
Z: Set on a zero result.
Reset otherwise.
V: Set on overflow into the sign bit.
Reset otherwise.
S: Set to a copy of the sign bit.
P: Parity flag set if result is even, reset if odd.
Addition
The contents of the accumulator are added to the second operand and the
results are left in the accumulator.
Action" Flags 8080 Mnemonic Z-80 Mnemonic
A^A + s C Z V S ADDs ADD A.s
ADIn
8080 and Z-80
Z-80 only
ADD
A
B
C
D
E
H
L
(HL)
n
(IX-i-d)
(lY-Kd)
OP code
87
80
81
82
83
84
85
86
C6n
DD86d
FD86d
Addition with Carry
The contents of the accumulator, the second operand, and the carry flag are
all added together and the result is left in the accumulator.
Action Flags 8080 Mnemonic Z-80 Mnemonic
A-^A + s + C C Z V S ADC s ADC A,s
ACI n
8080 and Z-80
Z-80 only
ADD
A
B
C
D
E
H
L
(HL)
n
(IX+d)
(lY+d)
OP code
8F
88
89
8A
8B
8C
8D
8E
CEn
DD8Ed
FD8Ed
Let's consider for a moment the purpose of an addition with carry.
Suppose we are dealing with two very long binary numbers. Each is so long
that it takes three bytes to hold the number: 23 magnitude bits and one sign
Byte 3 Byte 2 Byte 1
BIG A I I I
BIGB
A Method to Our Logic
33
The two numbers can be added using the accumulator and the following
game plan.
1. Load byte 1 of BIGA into the accumulator. Add byte 1 of BIGB. Store
the result.
2. Load byte 2 of BIGA into the accumulator. Perform an add-with-carry
with byte 2 of BIGB. Store the result.
3. Repeat step 2 using byte 3. Check for overflow. Store the result.
We could ignore the overflow flag when adding bytes 1 and 2. Overflow tells
us the sign bit is no longer reliable and bytes 1 and 2 have no sign bit.
Subtract and Subtract with Carry
In a subtract operation the value of the second operand is subtracted from the
contents of the accumulator and the result is left in the accumulator.
Action Flags 8080 Mnemonic Z-80 Mnemonic
A-^A-s C Z V S SUBs SUB s
SUIn
In a subtract with carry, the second operand and the carry flag are subtracted
from the accumulator and the result is left in the accumulator.
Action Flags 8080 Mnemonic Z-80 Mnemonic
A-^A-s-C C Z V S SBBs SBCA.s
SBIn
8080 and Z-80
Z-80 only
A
B
C
D
E
H
L
(HL)
n
(IX+d)
(lY+d)
Subtract
97
90
91
92
93
94
95
96
D6n
DD%d
FD96d
Subtract
with carry
9F
98
99
9A
9B
9C
9D
9E
DEn
DD9Ed
FD9Ed
AND, OR,andXOR
The action of these logical operators has already been discussed in detail in
"Bits, Bytes, and Boolean Operators." In each case the result is left in the
accumulator. The mnemonics and OP codes are summarized in the following
table.
34
Action
Flags
Z-80 and 8680 Assembly Langtiage Programming
8080 Mnemonic Z-80 Mnemonic
AND C*ZPS ANA s AND s
ANI n
OR C*ZPS ORA s OR s
ORI n
XOR C*ZPS XRA s XOR s
XRI n
*The carry flag is reset by all logical operations.
8080 and Z-80
Z-80 only
A
B
C
D
E
H
L
(HL)
n
(IX+d)
(lY+d)
AND
A7
A0
Al
A2
A3
A4
A5
A6
E6n
DDA6d
FDA6d
OR
B7
B0
Bl
B2
B3
B4
B5
B6
F6n
DDB6D
FDB6d
XOR
AF
A8
A9
AA
AB
AC
AD
AE
EEn
DDAEd
FDAEd
Compare Instruction
The compare operation is a subtraction with the answer thrown away. The
second operand is subtracted from the contents of the accumulator, but the
accumulator is left unchanged. Only the flags are affected.
Compare A: 17
s: 7
— s
0 0
0 1 0
0
0
1
0
0
0 0
0
1
1
1
0
0
0 0
1
0
1
0
Flag settings:
C: 0, no carry
Z: 0, not a zero result
V: 0, no overflow
S: 0, positive result
result
discarded
Compare A: 7
s: 17
— s
A 0 0 0 0 0
1
1
00010001
1
1
0
result
discarded
0
Flag settings:
C: 1 , borrow generated
Z: 0, not a zero result
V: 0, no overflow
S: 1 , negative result
A Method to Our Logic
35
The above examples illustrate that if we know for sure that the numbers
compared are both positive and both less than 128, then we know
A < s if S = 1 (negative result)
A = s if Z = 1 (zero result)
A > s if S = 0 and Z = 1 (positive nonzero result)
Similarly, the flag setting for ^ , ^ , and ^ can easily be determined.
Now suppose we interject the possibility of negative numbers in the
compare.
A:
s:
7
7
result
discarded
A
1
1
1
1
1
0
0
1
s
0
0
0
0
0
1
1
1
1
1
1
1
0
0
1
0
A:
s:
7
7
Flag settings:
C: 0, no borrow generated
Z: 0, not a zero result
V: 0, no overflow
S: 1 , negative result
result
discarded
A
0
0
0
0
0
1
1
1
s
1
1
1
1
1
0
0
1
0
0 0
0
1
1
1
0
Flag settings:
C: 1 , borrow occurred
Z: 0, not a zero result
V: 0, no overflow
S: 0, positive result
Again it appears that the flag settings discussed for positive numbers will
work. But suppose we try to compare 127 and - 127. This certainly makes
sense.
127
0
1
1
1
1
1
1
1
- 127
1
0
0
0
0
0
0
1
Z:
V:
1
1
1
1
1
1
1
0
S:
if we try to say that 127 <
- 127 because
Flag settings:
1 , borrow occurred
0, not a zero result
1 , overflow occurred
1 , negative result
negative, we are obviously talking nonsense. Does this mean then that we
cannot compare two numbers that we cannot subtract? If so, that would
impose a serious restriction on our ability to perform comparisons.
36
Z-80and 8080 Assembly Language Programming
A little analysis reveals the answer. The overflow flag is set when the sign
bit is clobbered. If the sign bit has been clobbered, it's just the opposite of
what we want for our test.
If V = 0 then
S = 0 =#>A> s
S = 1 =^ A < s
If V = I then
S = 0 =^ S should really be 1 so A < s
S = 1 =^ S should really be 0 so A > s
That's a lot of testing and it looks like it could turn into a lot of code. Now
suppose we perform an XOR (exclusive OR) between the overflow and sign
flags and compare the result to the chart above.
V S V XOR S Results from Chart Above
1
1
0
0
1
0
1
0
0
1
1
0
A > s
A < s
A < s
A > s
We can now see that
(V XOR S = 0) =^ A>s
(V XOR S = 1) A<s
We know we can get A > s by taking A > s and weeding out the case where A
= s. So now we can relate all the relationships between A and s to the
corresponding flag settings. Flag settings for a comparison of eight bit signed
numbers are:
Relationship Holds if Comment
(:?-;)
A< s VXORS = I
A< s VXORS = 1
or
Z = 1
A = s Z = 1
A + s Z = 0
A > s VXORS = 0
and
Z = 0
A >s VXORS = 0
We're still not through discussing the compare operation. What if the
values in A and s are not signed numbers? Instead of — 128 < A < 127, we
have 0 < A ^ 255. That would certainly be a valid interpretation of the eight
A Method to Our Logic
37
bits. Such a representation would be especially useful for counting. If, say, we
wanted to repeat a certain sequence of instructions 150 times, we may want to
compare our current count to this limit. How then shall we interpret the flag
settings?
Clearly the zero flag will still work for us. But now the sign and overflow flags
have no significance. It is the carry flag that will fill the gap. The carry flag is
set whenever a subtraction generates a borrow out of the register.
(C
(C
0)
1)
^ A > s
^ A < s
No sign bit means no overflow worries, so this chart is easy. The flag settings
for a comparison of eight bit unsigned numbers are
Relationship Holds if Comment
A< s
A< s
C = 1
C = 1
or
Z = 1
A =s
A =^s
A > s
A > s
Z = 1
Z = 0
C = 0
and
Z = 0
C = 0
/A>s\
I and I
With the compare operation fully analyzed, it's time to consider the
compare instruction. The action of a compare is described as (A - s) since it
is based on a subtraction operation. The fact that neither operand is affected
in the process is reflected in the absence of an arrow.
Action
Flags
8080 Mnemonic
Z-80 Mnemonic
(A - s)
cz vs
CMPs
CPI n
CPs
8080 and Z=80
Z-80 only
A
B
C
D
E
H
L
(HL)
n
(IX+d)
(lY-Kl)
Compare
BF
B8
B9
BA
BB
BC
BD
BE
FEn
DDBEd
FDBEd
Increment and Decrement Instructions
All of the arithmetic and logical instructions we have seen so far have dealt
with two operands, at least one of which was in the accumulator. By contrast,
38
Z-80and 8086 Assembly Language Programming
increment and decrement instructions have one operand and it can be con-
tained in one of the following registers.
8080
Source
Z-80
r
M
d(X)*
d(Y)*
♦TDLZ 80
Any eight bit register
The memory location
pointed to by the
HL pair
An indexed memory
location
(HL)
(IX + d)
(lY + d)
Again, any one of these will be referred to as s.
An increment adds one to the operand. A decrement subtracts one.
Action Flags 8080 Mnemonic Z-80 Mnemonic
s-*-s+ 1
s-^s - 1
Z VS
Z VS
INRs
OCRs
INCs
DECs
8080 and Z-80
Z-80 only
A
B
C
D
E
H
L
(HL)
(IX-Hd)
(lY-^d)
Increment
3C
04
0C
14
IC
24
2C
34
DD34d
FD34d
Decrement
3D
05
0D
15
ID
25
2D
35
DD35d
FD35d
Operations on A and F
Complement Accumulator
Complement is another logical operation. It differs from AND, OR, and
XOR in that it has only one operand. The complement operation is a I's
complement of the value, so every zero bit is changed to a one, and every one
to a zero. Often called a NOT operation, the complement can be summarized
in the following truth table.
A
NOT A
1
0
0
1
The NOT operation is repeated bit by bit for every bit in the accumulator.
A Method to Our Logic
39
1
0
1
1
0
0
0
1
0
1
0
0
1
1
1
0
Complementing the accumulator does not affect any of the flags we have
discussed so far. The OP code is 2F. The mnemonics are.
CMA (8080)
CPL (Z-80)
Negate Accumulator
The Z-80 has an instruction which allows the accumulator to be negated (2's
complement).
Action OP Code Flags TDL Z-80 and Z-80
A-« A ED 44 CZVS NEC
8080 programmers can substitute for NEG, since 2's complement is I's
complement plus 1 .
CMA
INR A
Complement and Set Carry Flag
The carry flag is the only flag which can be directly manipulated. Choices
include
Action OP Code 8080 Mnemonic Z-80 Mnemonic
C NOTC 3F CMC CCF
C 1 37 STC SCF
Missing is the ability to reset the carry. The easiest way to reset the carry is to
set it and then complement it. But there is a method which is twice as fast.
You will recall that any logical operation (except NOT) clears the carry, but
the logical operations affect the accumulator's contents unless the second
operand is also the accumulator. Clearly, two operations exist which clear the
carry and leave the accumulator intact. These are
8080 Z-80
ANA A AND A
ORA A OR A
Either of them makes a fine "clear carry flag" instruction.
40
Z-80and 8086 Assembly Language Programming
NOP Instruction
An oddity in the 8080 and Z-80 instruction repertoire is the NOP. With an
OP code of 00, the NOP has the distinction of being the instruction that does
nothing. The abihty to "do nothing" with a particular byte of code can prove
very valuable at times, especially during the debugging process.
16 Bit Arithmetic Instructions
There are no 16 bit logical instructions, and only a limited number of
arithmetic operations possible. 8080 programmers are limited to increment,
decrement, and addition. Increment and decrement can be performed on 16
bit registers BC, DE, HL, and SP. In 16 bit addition, register pair HL acts as
the accumulator. The other operand in the addition operation may be
registers BC, DE, HL, or SP.
The Z-80 programmer has more choices. The increment and decrement
instructions can be applied also to the IX and lY index registers, and other
add and subtract operations are possible. It is not possible, however, to add
the IX or lY index register to the HL pair. So, before we discuss the Z-80
extensions, let's summarize the instructions the two microprocessors have in
common.
To the 8080 programmer rr will mean any one of B for the BC register
pair, D for the DE pair, H for HL, or SP for the stack pointer. TDL Z-80 will
also include X for the IX index register and Y for the lY register.
To the Z-80 programmer rr will mean any one of BC, DE, HL, SP, IX, or lY,
Action Flags 8080 Mnemonic Z-80 Mnemonic
HL^HL + rr C DAD rr ADD HL,rr
rr-^rr + 1 none INX rr INC rr
rr<*-rr — 1 none DCX rr DEC rr
Note that since the overflow and sign flags are not set, 16 bit operations
must be handled carefully.
8080 and Z-80
Z-80 only
BC
DE
HL
SP
IX
lY
ADD
09
19
29
39
Increment
03
13
23
33
DD23
FD23
Decrement
0B
IB
2B
3B
DD2B
FD2B
Z-80 Extensions
The Z-80 instruction set also includes an add with carry and subtract with
carry that treat the HL as an accumulator. Again, the second operand may
A Method to Our Logic
41
be in registers BC, DE, HL, or SP. No pure subtract for 16 bit registers exists,
though the carry may first be cleared to achieve the equivalent of a pure
subtract.
Action Flags TDL Z-80 Mnemonic Z-80 Mnemonic
HL— HL + rr + c CZVS DADC rr ADC HL.rr
HL^HL + rr-C CZVS DSBC rr SBC HL.rr
Z-80 only
BC
DE
HL
SP
Add with
carry
ED4A
ED5A
ED6A
ED7A
Subtract
with carry
ED42
ED52
ED62
ED72
There are also Z-80 extensions which allow the IX and lY registers to act in
the role of accumulator.
Action Flags OP Code TDL Z-80 Mnemonic Z-80 Mnemonic
IX-^IX + BC
C
DD09
DADX
B
ADD
IX, BC
IX— IX + DE
C
DD19
DADX
D
ADD
IX, DE
IX— IX + SP
C
DD39
DADX
SP
ADD
IX, SP
IX— IX + IX
C
DD29
DADX
X
ADD
IX, IX
lY^IY + BC
C
FD09
DADY
B
ADD
IY,BC
lY-^IY + DE
C
FD19
DADY
D
ADD
IY,DE
lY— lY + SP
C
FD39
DADY
SP
ADD
IY,SP
lY— IY+ lY
C
FD29
DADY
Y
ADD
IY,IY
Exercises
Write a sequence of instructions that will sum a small array of three numbers.
The first number is pointed to by the HL pair, and the other two occupy the
following two bytes of memory. (You may assume no overflow will occur.)
HL
#1
#3
42
Z-Sfiand 8080 Assembly Language Programming
2. Write a sequence of instructions that would add BC and HL, leaving the
result in HL. (Assume 16 bit addition is not possible.)
3. A talent agency has discovered it can keep all the information needed about
the abilities of its clients in a single byte according to the following scheme.
Bit 7 — 1 Can dance
0 Can't dance
Bit 6 — 1 Can sing
0 Can't sing
Bit 5 — Can Act
0 Can't act
Bit 4—1 Does dramatic roles
0 Does not
Bit 3 — 1 Does comic roles
0 Does not
Bit 2 — 1 Is exceptionally attractive
0 Is not
Bit 1 — 1 Has experience
0 Has none
Bit 0 — 1 Female
0 Male
One such byte is in the accumulator. Tell what instruction will determine if
the person involved is a male, singer-dancer, who can act, does both comic
and dramatic roles, is experienced, but not exceptionally attractive. What
flag will contain the answer?
4. What flags will tell you if A < s and A is
a. a signed eight bit number
b. an unsigned eight bit number
5. There is no 16 bit compare instruction. Suppose two 16 bit signed variables
BIGA and BIGB must be compared. Describe in words a method to ac-
complish this.
6. The 8080 programmer has no 16 bit subtract. Write a sequence of in-
structions that will accomplish the subtraction (if overflow can be ignored) of
register pairs BC and HL. Leave the result in HL.
jumps, loops, and
modular programming
In the previous chapter we spent a good deal of time talking about the in-
terpretation of the flag settings after a compare. As yet, however, we have
said nothing about how to access the flags and read their values. Flag settings
are accessed by means of conditional statement. That is, a command to do
something if and only if a flag has a certain value. The instruction to be
performed can be a jump or a subroutine call.
Jump Instructions
The normal sequence of program execution is to perform each instruction in
turn from top to bottom. The following pattern is continuously repeated.
1 . Fetch the instruction.
2. Increment the program counter.
3. Execute the instruction.
A jump instruction alters the normal top-down flow. During execution of the
jump instruction (step 3) the address in the program counter is altered. Now,
when the next instruction is fetched, it is taken from a different place in the
program. So, the instruction to jump to location nn can be diagrammed as
PC-«- nn
The mnemonics and OP code are
OP Code 8080 Mnemonic Z-80 Mnemonic
C3 nn JMPnn JP nn
Consider the following sequence of instructions.
8080 Z-80
SUB A SUB A
LXI H, ARRAY LD HL, ARRAY
SPOT: ADD M SPOT: ADD A, (HL)
INX H INC HL
JMP SPOT JP SPOT
43
44
Z-80and 8080 Assembly Language Programming
The accumulator is cleared and register pair HL is set to point to the starting
address of an array in memory. This is the initialization phase of the loop.
The contents of the array location pointed to by the HL pair is added to the
accumulator. This is the body of the loop. The HL register pair is increased
by one. This is the increment phase of the loop. A jump back to spot closes the
loop.
However, something is dreadfully wrong here. There is no means of
terminating the loop. Left to its own, it would go on forever. When a con-
dition arises to terminate the loop, the jump back should no longer occur.
Suppose in our example we decide that we should only repeat the loop five
times. What we now need is a conditional jump. Here's the game plan.
1 . Set up in some eight bit register the number as a counter.
2. Every time the loop is repeated, decrement that register.
3. When that register goes to zero, don't jump back again.
So what we need is an instruction that performs the following action.
IfZ = 0, PC nn (jump on nonzero)
The instruction that will do this for us is
OP Code 8080 Mnemonic Z-80 Mnemonic
C2 nn JNZ nn JP NZ.nn
Now we can rewrite the sequence of instructions to add the first five
elements in the array.
8080 Z-80
SUB A
LXI H, ARRAY
MVI B,5
SPOT: ADDM
INX H
DCRB
JNZ SPOT
SUB A
LD HL, ARRAY
LD B,5
SPOT: ADDA, (HL)
INC HL
DEC B
JP NZ.SPOT
This loop can be broken up into four distinct phases. These four phases will
be present in every properly constructed loop:
1. Initialization
2. Body
Jumps, Loops, and Modular Programming
45
3. Increment
4. Test
If the four phases appear in the code in the above order, the loop is called a
post-test loop. A pre test loop will contain these phases in the following order.
1. Initialization
2. Test
3. Body
4. Increment
A loop of this form to perform our array sum would be more difficult to
construct, since we cannot rely on our decrement to set the zero flag on the
first pass. In fact, most pre test loops will be harder to code in a lower level
language. There is, though, a reason for their existence. Consider the
following diagrams.
Post-Test Pre -Test
Now consider the shortest route to Done for each:
Post -Test Pre -Test
1. Initialization 1. Initialization
2. Body 2. Test
3. Increment 3. Done
4. Test
5. Done
46
Z-SOand 808d Assembly Language Programming
Notice that in the post -test loop the body of the loop is always performed at
least once. In the pre test loop, it is possible to avoid performing the loop at
all. This then will be the criterion for selecting between the two:
If there is ever a case where the loop should not be performed at all, use
pretest.
Here is an example of a pre test loop to add the first five elements of an
array:
8080
SUB A
LXI H, ARRAY
MVI B,5
SPOT: MOVCA
MOV A,B
CMP 0
MOV A,C
JZ DONE
ADD M
INX H
DCR B
JMP SPOT
DONE:
Initialization
Test
Body
Increment
Z-80
SUB A
LD H, ARRAY
LD B,5
SPOT: LD C,A
LD A,B
CP 0
LD A,C
JP Z.DONE
ADD A,(HL)
INC HL
DEC B
JP SPOT
DONE:
Some comments about the test phase are in order. We first save the
contents of the accumulator in register C. Then we move the count into the
accumulator to compare it to 0. Now, before our conditional jump, we
restore the accumulator to the sum of the array. The move operation doesn't
affect the flags, so our jump on zero is still valid.
We now have two loops, one pre test and one post-test, that sum the first
five elements of an array. Both terminate properly, but are the results ac-
curate? We have made no test to see if overflow occurred at any point in the
series of additions. What we obviously need is a jump on overflow. Recall,
however, that the overflow flag is a dual purpose flag. It also serves as the
parity flag. Thus there is only one OP code for both. The 8080 assembler
provides two different mnemonics for the same OP code, the Z-80 only one, so
the programmer must himself keep track of the dual use. We can now
summarize the jump instructions.
Jumps, Loops, and Modular Programming
Action OP Code 8080 Mnemonic
47
Z-80 Mnemonic
PC^nn C3 nn JMPnn JP nn
IFZ=1, CAnn JZ nn JP Z,nn
PC-^nn
IFZ = 0, C2 nn JNZ nn JP NZ.nn
PC^nn
IFC=1, DAnn JC nn JP C,nn
PC^nn
IFC = 0. D2 nn JNC nn JP NC.nn
PC-»-nn
IFS=1, FA nn JM nn JP M.nn
PC-^nn
IFS = 0, F2 nn JP nn JP P,nn
PC^nn
IFP/V=1, EA nn JPE nn JPPE.nn
PC— nn JO nn
IFP/V = 0. E2 nn JPO nn JPPO.nn
PC-^nn JNO nn
We could then make our loop to sum the array more accurate by inserting
after the addition
JO OVFLOW 8080
J PE, OVFLOW Z-80
where OVFLOW would be an address in our program that does something
about the overflow problem. It may just print an error message and terminate
the program.
Z-80 Relative Jumps
Let's take another look at the OP code of the jump instruction.
C3 nn
We can see that it takes three bytes to store this instruction. Since an address
is two bytes long, it would seem to be impossible to shorten this instruction.
Yet it can be done. Remember that the program counter points to the address
48
Z-80and 8080 Assembly Language Programming
of the next instruction to be executed. Suppose that instruction will be a
jump. It is very likely that the jump will be to an address near where we are
currently. If that address is no farther away than - 128 to + 127 bytes, we can
express that address as a distance relative to the current location of the
program counter. That relative distance will fit in one byte.
PC
128
PC -
(next
instruction)
PC
127
•
•
•
Range of a
•
•
relative jump
•
•
•
The whole point of the relative jump instructions is this savings in space.
Take, for example, our original program rewritten with a relative jump.
TDLZ-80 Z-80
SUB A SUB A
LXI H, ARRAY LD HL, ARRAY
SPOT: ADD M SPOT: ADDA,(HL)
INX H INC HL
JMPR SPOT JR SPOT
The OP code for the relative jump instruction is
18e
where e is the magnitude of the relative jump as a signed number one byte in
length.
Ignoring for the moment the fact that this is an infinite loop, let's hand
assemble these instructions. Assume ARRAY is located at 3F00 and assume
that the program begins at 2000.
Address
Instruction
Action
2000
2001
2004
2005
2006
2008
97
21003F
86
23
ISe
A-^ A- A
HL*-3F00
A— A + (HL)
PC-^PC + e
Jumps, Loops, and Modular Programming
49
What should we use for e? Remember that the sequence of program execution
is
1. Fetch the instruction (get 18e).
2. Increment the program counter (PC = 2008).
3. Execute the instruction.
We want to jump to SPOT. SPOT is at location 2004, so we want to solve this
little equation:
2004 = 2008 -h e
Clearly e must be -4. In 2's complement:
4
0
0
0
0
0
1
0
0
4
1
1
1
1
1
1
0
0
Thus, at location 2006 in our program we would find
2006: 18FC
Fortunately, all this arithmetic is done for us by the assembler. We need only
use the relative jump instruction with the name of the location we want to
branch to.
Here, then, are the available relative jump instructions. Only the ab-
solute relative jump, relative jump on carry, and relative jump on zero are
provided.
Action
OP Code
TDL Z-80 Mnemonic
Z-80 Mnemonic
PC-^PC + e
18e
IFZ=1, 28 e
PC-^PC + e
JMPR nn*
JRZ nn
JR nn
JR Z,nn
IFZ = 0, 20e
PC^PC + e
JRNZ nn
JR NZ.nn
IFC = 1
PC^PC + e
38 e
JRC nn
JR C.nn
IFC = 0,
PC-^PC + e
30 e
JRNC nn
JR NC.nn
•Here the use of nn indicates the name of the destination.
50
Z-8/fand 8080 Assembly Language Programming
Z-80 Loop Instruction
There is another relative jump instruction available on the Z-80 that does
more than just jump or test and jump. The DJNZ provides the capability of a
built-in loop. Its action may be summarized as
B-^B - 1
ifB 0, PC^PC + e
The B register must first be set to the number of repetitions desired. Choices
range from 1 to 256 repetitions. By setting B to 1-255, the corresponding
number of repetitions are achieved. If B is initially set to 0, the first
decrement will leave B set to 255, so a total of 256 repetitions will occur before
B gets back to 0 again.
Let's repeat the loop that will sum the first five array elements.
TDLZ-80 Z-80
SUB A SUB A
LXI H, ARRAY LD HL. ARRAY
MVI B,5 LD B,5
SPOT: ADD M SPOT: ADD A,(HL)
INX H INC HL
DJNZ SPOT DJNZ SPOT
The OP code for the decrement-jump-nonzero instruction 10 e.
Register Indirect Jumps
The register indirect jump which the 8080 and Z-80 have in common can be
diagrammed as
PC^HL
That is, the address in the HL register pair becomes the address where the
next instruction will come from. The OP code and mnemonics are
OP Code 8080 Mnemonic Z-80 Mnemonic
E9 PCHL JP (HL)
So the following instruction sequences are equivalent
8080 Z-80
A.
SPOT: , SPOT: ,
JMP SPOT JP SPOT
Jumps, Loops, and Modular Programming
51
B.
SPOT:
SPOT:
LXI H.SPOT
PCHL
LD HL.SPOT
JP (HL)
At first sight the E9 one byte OP code would seem to be a great one byte
jump. These examples indicate, however, that its true cost is four bytes.
Three bytes are taken up by getting the address into the HL register.
Needless to say, this is not the most common form of a jump. Its main
value lies in code that must be capable of running at any address whatsoever
without requiring any modification. Such code is called self-relocating code.
Besides the use of the HL register pair for this purpose, Z-80 programmers
may also use the IX or lY registers.
Action OP Code TDL Z-80 Mnemonic Z-80 Mnemonic
Subroutines and Modular Programming
When a programmer is faced with any nontrivial task, he is well advised to
divide the task into individual modules or subroutines. In this regard we can
honestly say that no programming assignment is ever difficult. If a task seems
formidable break it down into smaller tasks, each of which can be easily
handled.
PC-^IX
PC-^IY
DDE9
FDE9
PCIX
PCIY
JP (IX)
JP (lY)
If a task seems too big . . .
A LESS
Q) FORMIDABLE TASK
just break it up . . .
and deal with the pieces one by one.
52
Z-80and 8080 Assembly Language Programming
This is modular programming or structured programming. Besides
making your life easier when you code the program, it makes the program far
easier to understand. Modularity can save space and programming effort if
sequences of instructions that must be repeated are written as subroutines
(program modules).
Subroutine calls are so easy on the 8080 and Z-80 that we can recom-
mend their use wholeheartedly to the earliest beginner to assembly language
programming. The basic instruction used to transfer control to a subroutine
is
CALLnn 8080 and Z-80
To get back, the basic instruction is
RET 8080 and Z-80
We can diagram the flow of control as follows.
MAIN
MYSUB
CALL MYSUB
RET
A CALL is like a jump with one difference. The return address is saved on the
stack. The return instruction pops the stack and jumps back to the address
left there.
That's all there is to it. CALL to get there. RET to get back. Everything
needed is done automatically.
You can also nest subroutine CALLs. That is, a subroutine can call a
subroutine of its own, and that subroutine can call another subroutine, and so
on. The nature of the stack is such that the return addresses will never get
mixed up. The program can always find its way back.
MAIN: *
CALL SUBA
empty stack SP
SUBA: •
CALL SUBB
SUBB:
SP
main s
address
Jumps, Loops, and Modular Programming
53
RET
RET
SP
SUBA's
address
main s
address
POPs SUBA's
return address
POPs main
return address
Calls to subroutines and returns from subroutines can be made con-
ditional on the setting of a flag. The instructions are nearly identical to the
conditional jumps. They are
Action OP Code 8080 Mnemonic Z-80 Mnemonic
CALL nn
IfZ=l,
CALLnn
CD nn
CC nn
CALL nn
CZ nn
CALL nn
CALL Z,nn
IfZ = 0,
CALLnn
C4 nn
CNZnn
CALLNZ.nn
IFC=1,
CALL nn
DC nn
CC nn
CALL C,nn
IfC = 0,
CALLnn
D4 nn
CNC nn
CALLNC.nn
IfS=l,
CALLnn
FC nn
CM nn
CALL M,nn
IFS = 0.
CALLnn
F4 nn
CP nn
CALL P,nn
IF P/V= 1,
CALL nn
EC nn
CPE nn
CALL PE.nn
If P/V = 0,
CALL nn
E4 nn
CPO nn
CNO nn
CALL PO.nn
54
Z-80and 8086 Assembly Language Programming
RET C9 RET RET
IfZ=l, C8 RZ RETZ
RET
IfZ = 0, C0 RNZ RETNZ
RET
IfC = l, D8 RC RETC
RET
IfC = 0, D0 RNC RETNC
RET
IfS=l, F8 RM RETM
RET
IfS = 0, F0 RP RETP
RET
IfP/V=l, E8 RPE RETPE
RET RO
IfP/V = 0, E0 RPO RETPO
RET RNO
The only complication possible in modular programming involves the
use of the registers. Most times both the main program and the subroutine
would like full use of the registers. How can the subroutine use all of the
registers without messing up their contents for the main program? The answer
is simple. The subroutine need only PUSH all of the register values onto a
stack, do its thing, and then POP the original contents back in before
returning to the main program.
Exercises
1. Suppose VARA and VARB are two unsigned, one byte variables, and the
following instruction sequence is executed.
8080 Z-80
LDA VARA LD A, (VARA)
LXI H,VARB LD HL,VARB
CMP M CP (HL)
Jumps, Loops, and Modular Programming
55
Write a sequence of instructions that will branch to SPOT if
a. VARA < VARB
b. VARA < VARB
c. VARA = VARB
d. VARA VARB
e. VARA > VARB
f. VARA > VARB
2. Repeat exercise 1 if VARA and VARB are signed numbers.
3. Write a subroutine which accepts as inputs
a. the address of an array in a variable named ARYADR
b. the number of elements in the array in a variable named SIZE
and produces the following outputs.
a. The sum of all of the array elements left in the accumulator, if no
overflow is produced
b. if overflow occurs, the value 1 left in the variable named OVFLAG. The
value returned in the accumulator may be assumed to be meaningless.
No registers except the AF pair may be altered upon return to the main
program.
4. Two 16 bit unsigned variables occupy memory locations BIGA and BIGB.
Write a sequence of instructions that will call a routine named ABIGR if
BIGA > BIGB, and BBIGR if BIGA < BIGB.
5. Repeat exercise 4 if BIGA and BIGB are 16 bit signed variables.
6. For this exercise refer to exercise 3 in the section "A Method To Our Logic."
In addition to the assumptions made in that exercise, assume further that the
agency keeps the information about its clients in the following form.
Location
Descriptive
Jump
byte
address
PEOPLE
1
1
PEOPLE + 3
2
2
PEOPLE + 6
3
3
PEOPLE + 9
4
4
•
•
•
•
•
•
•
•
•
The array is named PEOPLE. For each client in the array, there is a
descriptive byte and the address of a segment of code that prints out that
person's name, address, phone number, etc. The variable named COUNT
contains the number of clients currently being serviced. Write a segment of
56
Z- 80 and 8080 Assembly Language Programming
code that will look for the type of person described in the previously men-
tioned exercise 3. If such a person is found, control should pass to the jump
address for the person. If no such person is contained in PEOPLE, the sub-
routine named NOSUCH should be called.
bit fiddling and
message making
How can the Z-80 programmer manipulate single bits of data? How do you
rotate registers and why would you want to? How are alphabetic characters
stored in computer memory? How do you get data into and out of the
computer? These are just some of the questions that will be answered in this
chapter.
Z-80 Bit Manipulation Instructions
The Z-80 has the capability of testing, setting, or resetting individual bits
within a byte. The bits are numbered from low order to high order.
7 6 5 4 3 2 1 0
The byte whose bits are being manipulated may be located in any one of the
following areas, any one of which will be referred to as s.
TDL Z-80 Location Z-80
r Any eight bit register r
M The memory location (HL)
pointed to by the
HL pair
d(X) An indexed memory (IX + d)
location
d(Y) (lY + d)
The bits in byte s will be referred to by number. The letter b will be used to
stand for any bit number 0-7. Thus,
refers to any bit in any of the above locations.
57
58
Z-Sdand 838/f Assembly Language Programming
The bit test instruction sets the zero flag to the opposite of the bit value.
Worded differently, the bit test instruction sets the zero flag if the bit has a
zero value and resets it otherwise. Diagrammatically,
s |b|
The mnemonics for both TDL Z-80 and Z-80 are the same.
BIT b.s
The chart of OP codes is large.
Bit Test
Bit
A
B
C
D
E
H
L
(HL)
(IX+d)
(lY+d)
0
CB47
CB40
CB41
CB42
CB43
CB44
CB45
CB46
DDCBd46
FDCBd46
1
CB4F
CB48
CB49
CB4A
CB4B
CB4C
CB4D
CB4E
DDCBd4E
FDCBd4E
2
CB57
CB5(J
CB51
CB52
CB53
CB54
CB55
CB56
DDCBd56
FDCBd56
3
CB5F
CB58
CB59
CB5A
CB5B
CB5C
CB5D
CB5E
DDCBd5E
FDCBdSE
4
CB67
CB6(J
CB61
CB62
CB63
CB64
CB56
CB66
DIX:Bd66
FDCBd66
5
CB6F
CB68
CB69
CB6A
CB6B
CB6C
CB6D
CB6E
DDCBd6E
FDCBdGE
6
CB 77
CB7(J
CB71
CB72
CB73
CB74
CB75
CB76
DDCBd76
FDCBd76
7
CB7F
CB78
CB79
CB7A
CB7B
CB7C
CB7D
CB7E
DDCBd7E
FDCBd7E
The bit set instruction sets the indicated bit.
s jb}-l
The mnemonics for both TDL Z-80 and Z-80 are again the same.
SET b,s
Again, there are many OP codes involved.
Bit Set
Bit
A
B
C
D
E
H
L
(HL)
(IX-Hd)
(lY+d)
CBC7
CBCU
CBCl
CBC2
CBC3
CBC4
CBC5
CBC6
DDCBdCe
FDCBdCe
1
CBCF
CBC8
CBC9
CBCA
CBCB
CBCC
CBCD
CBCE
DDCBdCE
FDCBdCE
2
CBD7
CBD0
CBDl
CBD2
CBD3
CBD4
CBD5
CBD6
DDCBdDG
FDCBdD6
3
CBDF
CBD8
CBD9
CBDA
CBDB
CBDC
CBDD
CBDE
DDCBdDE
FDCBdDE
4
CBE7
CBE<t
CBEl
CBE2
CBE3
CBE4
CBE5
CBE6
DDCBdE6
FDCBdE6
5
CBEF
CBE8
CBE9
CBEA
CBEB
CBEC
CBED
CBEE
DDCBdEE
FDCBdEE
6
CBF7
CBF0
CBFl
CBF2
CBF3
CBF4
CBF5
CBF6
DDCBdF6
FDCBdF6
7
CBFF
CBF8
CBF9
CBFA
CBFB
CBFC
CBFD
CBFE
DDCBdFE
FDCBdFE
This bit reset instruction resets the indicated bit.
s |b}^
Once again TDL Z-80 and Z-80 mnemonics are the same.
RES b,s
Bit Fiddling and Message Making
59
The OP codes are
Bit Reset
i>il
A
/\
R
D
c
n
r
H
X 1
L
1 lY+d)
CB87
CB8(»
CB81
CB82
CB83
CB84
CB85
CB86
DDCBd86
FDCBd86
1
CB8F
CB88
CB89
CB8A
CB8B
CB8C
CB8D
CB8E
DDCBdSE
FDCBd8E
2
CB97
CB90
CB91
CB92
CB93
CB94
CB95
CB96
DDCBd96
FDCBd96
3
CB9F
CB98
CB99
CB9A
CB9B
CB9C
CB9D
CB9E
DDCBd9E
FDCBd9E
4
CBA7
CBA(J
CBAl
CBA2
CBA3
CBA4
CBA5
CBA6
DDCBdA6
FDCBdA6
5
CBAF
CBA8
CBA9
CBAA
CBAB
CBAC
CBAD
CBAE
DDCBdAE
FDCBdAE
6
CBB7
CBBd
CBBl
CBB2
CBB3
CBB4
CBB5
CBB6
DDCBdBo
FDCBdB6
7
CBBF
CBB8
CBB9
CBBA
CBBB
CBBC
CBBD
CBBE
DDCBdBE
FDCBdBE
Rotate and Shift Instructions
Rotate instructions common to the 8080 and Z-80 microprocessor all involve
the accumulator. There are four basic types.
Rotate left circular
7^
•0
□
Rotate right circular
Rotate left
■0
□
Rotate right
Action OP Code
8080 Mnemonic
Z-80 Mnemonic
Rotate left
circular
07
RLC
RLCA
Rotate right
circular
0F
RRC
RRCA
Rotate left
17
RAL
RLA
Rotate right
IF
RAR
RRA
Before we go into those rotate and shift instructions u^hich are exclusively Z-
80, let's spend a moment discussing why you might want to rotate a register.
Suppose the accumulator has the following value.
0001 0010 = 18
60
Z-Sdand 8080 Assembly Language Programming
Then suppose we clear the carry and rotate the accumulator left. It will then
contain
0 0
1 0 0
1
0 0 = 36 = 18X 2
Suppose instead we had rotated right. The accumulator would have had
0 0
0 0 1
0
02j = 9=18-2
So shift and rotate instructions give us the capability to multiply and divide by
powers of two. We are now ready for a generalized algorithm that can be used
for multiplication and division in the 8080 and Z-80.
Multiplication and Division
The 8080 and Z-80 microprocessors possess no built-in multiply or divide
instructions, so subroutines must be written to provide this capability. We will
discuss here algorithms that can be used for positive integers.
The multiplication table for binary numbers isn't long.
0X0 = 0
0X1 = 0
1X0 = 0
1X1 = 1
Multiplication of longer numbers is done in the same way as in the decimal
system.
110 0 111
X 10 1
110 0 111
0 0 0 0 0 0 0
110 0 111
1 0 0 0 0 0 0 0 1 1
Notice that every line in forming the product is either a copy of the
multiplicand or all zeroes. The pattern of shifting each row one place to the
left is common to decimal multiplication.
Multiplication is notorious for generating large numbers. Assuming both
multiplier and multiplicand are one byte signed numbers, how large can the
product become? Obviously it's 127^ = 16,129. We are way over one byte in
length, but well within two bytes. In fact, if we assume multiplier and
multiplicand are one byte unsigned numbers the product will still fit in a 16
bit unsigned result. The multiply routine will therefore accept as inputs two
one byte signed or unsigned positive integers and produce as output a two
byte product of the two.
Bit Fiddling and Message Making
61
The method to be used parallels the approach used above. We will need
three registers for this operation. One will contain the multiplier, one the
multiplicand, and one we will clear for use as a work area.
1 & 2
00000000
multiplier
multiplicand
Registers 1 and 2 will be used to contain the result. Register 3 will be left
unchanged.
So our example above would begin as
1 & 2
0000000000000101
0 110 0 1 11
The following two steps will then be repeated eight times.
A. Check bit 0 of register 2 (the multiplier). If it is set, add the contents of
register 3 (the multiplicand) to register 1. If the bit is 0, do not add in
the multiplicand. After this step we would have
1& 2
0110011100000101
0 110 0 111
B. Shift registers 1 and 2 right one bit. At the end of the first iteration we
have
001 1001 l|l0000010|
Continuing this sequence for our sample case gives, on iterations 2-8,
2. A.) No addition
B.) Shift giving:
0001100111000001
3. A.) Add multiplicand + [01100111
100000001 1000001
B.) Shift giving:
4. A.) No addition
B.) Shift giving:
5. A.) No addition
B.)jShift giving
6. A.) No addition
B.) Shift giving
0100000001 100000
0010000000110000
000100000001 1000
000010 0000001 100
62
Z-80and 8086 Assembly Language Programming
7. A.) No addition
B.) Shift giving
8. A.) No addition
B.) Shift giving
00000100000001 10
000000100000001 1
Thus v^e can see that the result agrees with the long-hand computation.
Division is also extremely simple when the dividend and divisor are in
binary. Consider the following example.
1000111 r 1000
1101
1110100011
1101
11000
1101
10111
1101
10101
1101
1000
We knew that in multiplication if we allowed two bytes for a product and
restricted inputs to one byte, we could never run into difficulties with over-
flow. Following that lead, we might decide to use a two byte dividend, a one
byte divisor, and expect quotient and remainder to each remain within one
byte. But here we are not so lucky. In the above case the dividend will fit
within two bytes, but if we divide it by one the quotient will certainly not fit
within a byte. So in our division algorithm we will have to be on the lookout
for a means of deducing that our result is inaccurate. Again, all inputs will be
assumed to be positive integers. We will again need three registers. Registers 1
and 2 will contain the two byte dividend. Register 3 will contain the divisor.
Our example above would begin as
1&2
0000001110100011
0 0 0 0 1 1
The following three steps will be repeated eight times.
A. Registers 1 and 2 are shifted left one bit.
0000011101000110
B.The contents of register 3 (the divisor) is subtracted from register 1.
1 & 2
0000011101000110
0 0 0 0 1 1 0 1
1 & 2
111110 10
0 1 0 0 0 1 1 0
Bit Fiddling and Message Making
63
C.If the result of the subtraction causes a negative number to result in
register 1, the divisor is added back. If not, bit 0 of register 2 is changed
to A 1. In this case, a negative result occurred, so we add the divisor
back getting: the same contents as after step A.
Follov^ing our example through to the end gives
2.A.) Shift left:
0 0 0 0 1 1 1 0
1 0 0 0 1 1 0 0
B.) Subtract:
0 0 0 0 1 1 0 1
0 0 0 0 0 0 0 1
1 0 0 0 1 1 0 0
C.) Set bit 0:
0 0 0 0 0 0 0 1
1 0 0 0 1 1 0 1
3. A.) Shift left:
B.) Subtract:
0000001 10001 1010
0 0 0 0 1 1 0 1
11110 110
0 0 0 1 1 0 1 0
C.) Add back:
0 0 0 0 0 0 1 1
0 0 0 1 1 0 1 0
4. A.) Shift left:
B.) Subtract:
0 0 0 0 0 1 1 0
0 0 110 10 0
0 0 0 0 1 1 0 1
111110 0 1
0 0 110 10 0
C.) Add back: +
0 0 0 0 0 11 0
0 0 1 10 10 0
5. A.) Shift left:
B.) Subtract:
0 0 0 0 1 1 0 0
0 1 10 10 0 0
0 0 0 0 1 1 0 1
1111111101101000
C.) Add back: +
0 0 0 0 1 1 0 0
0 110 10 0 0
6. A.) Shift left:
0 0 0 1 1 0 0 0
1 1 0 1 0 0 0 0
B.) Subtract:
0 0 0 0 1 1 0 1
0000101 1 1 1010000
C.) Set bit 0:
0 0 0 0 1 0 1 1
1 1 0 1 0 0 0 1
64
Z-86and 8080 Assembly Language Programming
7.A.) Shift left:
B.) Subtract:
00010111 10100010
0 0 0 0 1 1 0 1
000010101010001
C.) Set bit 0:
8.A.) Shift left:
B.) Subtract:
0000101010100011
00010101010001 10
0 0 0 1 1 0 1
00001000010001 10
C.) Set bit 0:
00001000010001 1 1
At the conclusion of the division operation we have
1 &2
Remainder
Quotient
A check of our original example shows that we obtained the correct answer.
But what about our potential overflow? If we had begun with the
dividend used in the previous example, but made the divisor the number 1,
we know the result would overflow. But how would we know this happened?
A complicated chain of reasoning will reveal an extremely simple test.
We want to trap the quotients that won't fit in one byte. The largest signed
number that will fit is + 127. So we want to know about it whenever
Dividend >
Divisor
or
or
Dividend > 128 x Divisor
Dividend > Divisor
128
So a first try might be to divide the dividend by 128 and compare. Fortunately
128 — 2^ so we can do this by shifting right seven bits. Let's try this on our
sample case and see what we get.
Before:
000000 1110100011
After:
00000000
0 0 0 0 0 1 1 1
Bit Fiddling and Message Making
65
We lost all the contents of the high order byte. This will always be true
whenever a positive number is input. So we only have one byte left. Compare
it to the contents of the high order byte, if we shift one bit to the left.
0000011101000110
We can see that they match. What has this gotten us?
In the first step of the division algorithm, we shift one bit to the left. We
have seen that the high order byte then contains
Dividend
128
In the second step of the algorithm we subtract the divisor from the high
order byte.
Dividend \ .
^ Divisor
128
Here is our compare. It is done in the normal course of the algorithm!
Now notice that the third step of the algorithm has us setting bit 0 if the
result of the subtraction was not a negative number. So if the bit is set it
means
Dividend . Dividend ^ ^. .
Divisor or > Divisor 0
128 128
This is exactly the overflow we were looking for.
Now a second try emerges. Simply check the first iteration. If the sub-
tract step doesn't produce a negative result, we're headed for overflow. Before
we decide on this method, though, let's see what happens to this bit. At the
end of the first iteration it is set, so the result contains
1 & 2
xxxxxxxx
xxxxxxx 1
Seven more iterations remain. With each iteration that bit will be shifted one
place to the left. Thus at the end of the algorithm it will appear as
1 & 2
xxxxxxxx
Ixxxxxxx
Right in the sign bit itselfl
The final result of all this analysis couldn't be simpler:
A negative result indicates overflow.
We know that if dividend and divisor are both positive the result will always
be positive. So this gives us an unfailing check.
66
Z-80and 8080 Assembly Language Programming
Z-80 Rotate and Shift Instructions
In all of the rotate instructions we have discussed so far, the location of the
operand was always the accumulator. The Z-80, however, permits rotation
and shifts of operands located in any of the following areas
TDL Z-80
Location
M
d(X)
d(Y)
Any eight bit register
The memory location pointed
to by the HL pair
An indexed memory location
Z-80
(HL)
(IX + d)
(lY + d)
Any of these locations will be referred to as s. The possible types of rotations
are the same as those for the accumulator.
Action
TDL Z-80 Mnemonic
Z-80 Mnemonic
Rotate left
circular
RLCR
RLC
Rotate right
circular
RRCR s
RRC s
Rotate left
Rotate right
RALR s
RARR s
RL s
RR s
OP codes are as follows.
A
B
C
D
E
H
L
(HL)
(IX+d)
(lY+d)
Rotate left
circular
CB07
CB00
CB01
CBd2
CBOS
CBd4
cBas
CB(»6
DDCBd«>6
FDCBd(j6
Rotate right
circular
CBiF
CB08
CB09
CBtfA
CB0B
CB(JC
CB(JD
CB0E
DDCBdiE
FDCBd(JE
Rotate left
CB17
CB10
CBll
CB12
CB13
CB14
CB15
CB16
DDCBdie
FDCBdie
Rotate right
CBIF
CB18
CB19
CBIA
CBIB
CBIC
CBID
CBIE
DDCBdlE
FDCBdlE
Besides these extended rotate instructions, the Z-80 possesses the
capability to perform shifts on any of the locations s described above. The
possible shift instructions are
Bit Fiddling and Message Making
67
Shift left arithmetic
•0
0
Shift right arithmetic
-►0
Notice that in the shift right arithmetic a zero does not shift in on the left.
Instead, the sign bit is repeated to preserve the sign of the number. A pair of
examples should make this clear. In each assume that the carry flag was
initially cleared.
Effects of the shift
right arithmetic:
A. Before
After
After
0
1
0
1
0
1
0
'!
0
0
1
0
1
0
1
1
0
1
0
1
0
1
e
1
1
0
1
0
1
0
1
0
Shift right logical:
0 *- 7
-►0
C
Notice that no shift left logical is needed, since it would not be any different
than a shift left arithmetic.
The mnemonics are
Action TDL Z-80 Mnemonic
Z-80 Mnemonic
Shift left
arithmetic
SLAR s
SLA s
Shift right
arithmetic
SRAR s
SRA s
Shift right
logical
SRLR s
SRL s
The OP codes are
A
B
C
D
E
H
L
(IX+d)
(lY+d)
Shift left
arithmetic
CB27
CB20
CB21
CB22
CB23
CB24
CB25
CB26
DDCBd26
FDCBd26
Shift right
arithmetic
CB2F
CB28
CB29
CB2A
CB2B
CB2C
CB2D
CB2E
DDCBd2E
FDCBd2E
Shift right
logical
CB3F
CB38
CB39
CB3A
CB3B
CB3C
CB3D
CB3E
DDCBd3E
FDCBd3E
Two final rotate instructions available in the Z-80 are of great use in
binary coded decimal (BCD) arithmetic. Although this forms the subject of a
68
Z-80 and 8086 Assembly Language Programming
later chapter, the instructions will be presented here for completeness. The
TDL Z-80 and Z-80 mnemonics are identical. The operands are always the
contents of the accumulator and the memory location pointed to by the HL
pair.
Rotate left
digit (RLD)
OP code
ED6F
0
(HL)
I
T
0
Rotate right
OP code
A
7 4
3
0
digit i^KD)
ED67
i
(HL)
7 4
3 0
1
Character Representation Using the ASCII Code
We have already seen that a byte of memory may have many uses. It can
contain an instruction OP code or a piece of data, part of an address or an
immediate within an instruction. We will see now that a byte may also
contain the coded representation for a character.
What if a programmer wishes to store customer names in memory? Since
he has only numbers to deal with, some type of correspondence between
letters and numbers must arbitrarily be made. The ASCII code is the most
common code used in microcomputers. It is basically a seven bit code, though
many systems use the high order bit to signal a graphics character. A com-
plete chart of ASCII is included for reference in Appendix B. Notice that
there is a character 1 which in ASCII is hexadecimal 31 .
All input from the keyboard and output to screen or printer is usually
done in ASCII code. Once in the machine, characters can be stored in ASCII
or converted to some other convenient form. For example, suppose we read in
the number 123. In character form this is 313233^^ and occupies three bytes.
To use this as a value within our program we will have to convert it to binary.
After conversion it v^dll fit into a byte.
Notice that ASCII contains representations for both A and a.
A = 41
a = 61
Many printers can only handle upper case. Any lower case letter can be
converted to upper case by subtracting 20^^. This is often referred to as
folding to upper case.
1
Bit Fiddling and Message Making
69
Whether the programmer will have to write little utility routines to
convert to binary and back again or to fold characters to upper case will
depend on the kind of work he is doing. Nearly all programs, however,
require some sort of 1/ O (input/output).
A check of the instruction repertoire of the 8080 will reveal some nice
input and output instructions, but the casual programmer will never use
them: The monitor generally performs all I/O for the user. Although this
arrangement is a tremendous convenience for the user, it is a tremendous
headache for the instructor and for the novice programmer. There is no
standard, set way of doing I/O. Monitors differ in both techniques of use and
range of options. The simplest output technique requires the user to place a
single character in a given eight bit register and call a routine that displays or
prints it. Input under such a system is also a call to a fixed routine. Upon
return, the character input can be found in a given eight bit register.
Exercises
1 . Write a subroutine that will accept as inputs two eight bit positive numbers
located in variables named MLTPLR and MLTCND. The routine should
multiply them and output a two byte result in a variable named PRODCT.
Save any registers used by the subroutine.
2. Repeat exercise 1 if MLTPLR and MLTCND cannot be assumed to be
positive. (Hint: Test first. Complement each if necessary. Complement result
if necessary. For the multiply itself, call the routine in exercise 1 .)
3. Write a routine which will accept as inputs a two byte variable named
DIVDND and a one byte variable named DIVSOR. (Both may be assumed to
be positive.) The routine should divide DIVDND by DIVSOR and output the
one byte quotient and remainder in variables named QOTENT and
RMANDR, respectively. If an overflow occurs, set RMANDR to a flag value
of - 1.
4. For this exercise, refer to exercise 6 in "Jumps, Loops, and Modular
Programming." Write a subroutine that will sort the array PEOPLE into two
arrays called WOMEN and MEN. Keep track of how many elements are in
each array and store those values in suitably named variables.
5. Write a subroutine that will accept as inputs the two byte address of an array
of characters in a variable named WHERE and the number of characters in a
variable named DIGITS. All of the characters should be the ASCII code of
binary digits, i.e. ,
0 = 30H
1 = 31h
The subroutine should convert the character string into a single binary
number and leave its value in a two byte memory location named RESULT.
70
Z-80and 808fi Assembly Language Programming
6 . Repeat exercise 5 using
a. all characters hexadecimal digits
b. all characters decimal digits
(Hint: You may want to call the multiply or divide routines already written.)
7. Repeat exercises 5 and 6, going the other way. That is, accept a two byte
RESULT in binary, output the characters in the array, and store the number
of digits required in DIGITS.
8. Learn how I/O is handled through the monitor on your system.
a casual introduction
to data structures
Up to now we have referred to variables as things which somehow already
were in existence. We blithely said things like "Assume BIGA and BIGB are
16 byte variables in memory." Yet we have never hinted at how they got there.
By now we are used to writing instructions in mnemonic form and letting the
assembler convert them to OP codes and addresses. We will do basically the
same thing for variable declaration, but the mnemonics used to reserve space
for variables depend on the individual assembler you are using. The most
common choices are to
1 . Declare a one byte storage area and assign it an initial value.
LILVAR: .BYTE 77
2. Declare a two byte storage area and assign an initial value.
BIGVAR: WORD 777
3. Reserve a stated number of bytes of storage with no initial values
assigned to them.
ARRAY: BLKD 7
(In this example we get 7 bytes of storage reserved. Only the first byte
has a name.)
It would be a good idea for you to take the time right now to find out what key
words your assembler wants you to use in reserving space for your variables.
Using the Single Variable
A single variable, whether one byte or two bytes in length, can be accessed
directly through its name.
8080 Z-80
LDA LILVAR LD A, (LILVAR)
LHLD BIGVAR LD HL. (BIGVAR)
71
72
Z-Sdand 8080 Assembly Language Programming
The Array
We have already made several references to arrays, drawing on previous
experience and the context to provide meaning. Basically, whenever there was
more than one of anything, we called it an array. To be more accurate, an
array is a collection of like items. Usually only the first element of the array is
named. So our sample array from example C above would appear as
ARRAY
111
12)
ill
(5)
(6)
(Z)
1023
1024
1025
1026
1027
1028
1029
In higher level languages, we would typically access the elements by sub-
scripting.
ARRAY(3)
But in assembly language we would have to write
ARRAY + 2
to get the correct address in memory. The trick is getting used to counting:
Typical arrays are dealt with in loops. For example, we can add one to the
value of every element in an array. If the individual elements are single bytes,
this probably only requires setting up the start address in the HL pair and
looping through the array.
Multi-Dimensional Arrays
Suppose we wish to represent in computer memory an array that is, say, 4 X
5. It is convenient for us to think of our storage as a block
A Casual Introduction to Data Structures
73
Columns
0 12 3 4
Rows 0
1 ~~~~~
2
3 I
even though the bytes are arranged Hnearly in memory, what must be done
before this can be accompHshed is to decide on what order the elements
should appear in memory. There are two most likely choices.
0
1
2
3
4
0
1
2
3
4
0
0
1
2
3
4
0
0
4
8
12
16
1
5
6
7
8
9
1
1
5
9
13
17
2
10
11
12
13
14
2
2
6
10
14
18
3
15
16
17
18
19
3
3
7
11
15
19
A. Row major order B. Column major order
Locating a specific box will depend on the choice of representation used.
Row major order
Box # = col. # + (row #) * (total # of cols.)
Column major order
Box # = row # + (col. #) * (total # of rows)
This whole concept can be extended to three- and four-dimensional arrays
when needed.
The Structure
Closely allied to the concept of the array is the structure. Where an array is a
collection of like items, a structure is a collection of items which are not
necessarily alike.
For example, consider a collection of customer entries:
CUSTNO NAME ADDRSS PHONE
7 bytes
20 bytes
30 bytes
^(—7 bytes
^
74
Z-80 and 8080 Assembly Language Programming
Here a whole customer entry is 64 bytes long. (This turns out to be a very
convenient size.) So if we have a pointer to the start of one entry and we want
to get to the next we need only add 64. The individual fields of the entries are
all fixed displacements from the start of the entry.
Field Displacement
CUSTNO 0
NAME 7
ADDRSS 27
PHONE 57
Most assemblers allow the programmer to write an equate statement.
That is, to create a word that can be used in place of a number. Again, the
key word to do this varies from assembler to assembler.
TWO = 2
or
TWO EQU 2
Once an equate has been written, the assembler will translate all references to
it to the appropriate value. The use of equates adds greatly to the readability
of the program.
Getting around in a structure always involves using these displacements,
so it is a prime candidate for the indexed instructions which the Z-80 offers.
Suppose the IX index register points to one of the customer entries. We can
put the first letter of the customer's name into the C register with
TDL Z-80 Z-80
MOV C,NAME(X) LD C,(IX + NAME)
(Assuming, of course, that we first wrote an equate statement telling the
assembler that by the word "NAME" we really mean the number 7).
Do you see how much clearer the above instruction is than the following?
MOV C,7(X) LD C,(IX + 7)
This is the beauty of an equate.
8080 programmers must perform an addition to achieve the desired
result. Suppose the HL pair points to one of the customer entries. We can put
the first letter of the customer's name into the C register with
PUSH H Save original pointer
LXI D.NAME Displacement value in DE
DAD D Add in displacement
MOV C, M Get first letter of name
The task takes a little longer without the indexing capability.
A Casual Introduction to Data Structures
75
Achieving Variable Displacement in the Index Instructions
The Z-80 index instructions always involve a fixed, signed displacement d.
Oftentimes a programmer may desire to have the displacement vary. Variable
displacement can be achieved as follows.
d
IX
Effective address
(IX)
(IX+d)
Suppose we wish to access locations of varying displacement from a table
which begins at hexadecimal location 137B. We know that the effective
address of an index instruction is the contents of the IX index register plus the
fixed displacement. If, for example, the displacement were 5
IX
13
7B
DC
Addr. hi^
Addr. low
+ d
05
+ d
Displacement
Effective
address
13
80
Effective address
Now we know we always want the same starting location for the table,
but we want to vary the displacement. So let's switch things around a little.
First, notice that we get the same effective address with
IX
13 05
IX
Addr. high
Displacement
+ d
7B
+ d
Addr. low
13 80
Same effective address
But here the variable part is in the IX index register where we can get at it to
change it, while the table address that never changes anyway is in the fixed d.
We will shortly summarize the program steps that will accomplish this
goal, but first we have to take a close look at what we have here. Remember
that the displacement d is a signed number ( - 128 < d < 127), but the low
order byte of an address is an unsigned number (0 < addr. low < 256). So
suppose we tried the same switch using a table that starts at 13FF and a
desired displacement of 5.
13 05
FF
13 04
76
Z-80and 8080 Assembly Language Programming
The FFp^ = — 1, so 1305 — 1 = 1304 would be used as the effective address,
though it is hardly the desired result.
The solution centers around the concept of boundary alignment and
the 256 byte page. The first address in any microcomputer is 0000^; the last is
FFFFj^. Memory can be considered to be divided into 256 byte pages as
follows.
0000
• Page 0 The start address of any page of memory is of the
00FF form
0100
•
•
• •
Page 1
01 FF
0200
•
•
•
Page 2
02FF
XX00
So the high order address byte can be anything, but
the low order address byte is always 00, for any
address that is aligpied on an even page boundry.
etc.
Forcing this boundary alignment is sometimes essential. The means by which
this is accomplished is the origination or location statement. The key word
used is again dependent on the assembler, but ORG and LOG are common.
.LOG 1000H
This would set the next location declared to hexadecimal address 1000.
If we wish to use variable displacement to access an array named
TABLE, we need to make use of a reference location we call TBASE, which is
aligned on an even page boundary. TABLE itself may lie anywhere in the
range TBASE - 128 to TBASE +127. The distance between TABLE and
TBASE will then be a one byte signed number. We use this d as the fixed dis-
placement called for in the index instruction. We use the high order byte of
TBASE as the high order portion of the index register. The variable displace-
ment forms the low order portion of the index register. This variable displace-
ment will now be an unsigned number in the range 0 to 255.
IX
XX
Variable displ.
where -128 ^ d < 127, 0 < var. displ. < 255.
TABLE
TBASE
(XX00)
A Castuil Introduction to Data Structures
77
With the object clearly in mind, there remains only one question. How
do we get a one byte variable displacement into the low order half of the index
register? The answer is that we plan ahead and reserve for ourselves a two byte
area to which we have given the value XBASE (XX00).
INDEX: .WORD XBASE
Now the value of XBASE will be stored in memory in swapped form.
INDEX-
XX
Xhen suppose our variable displacement is contained in the one byte memory
location named DISPL. Xhe following sequence of instructions will set up the
IX index register.
XDLZ-80
LDA DISPL
SXA INDEX
LIXD INDEX
Z-80
LD A, (DISPL)
LD (INDEX), A
LD IX, (INDEX)
Linked Structures
All other data structures we have discussed so far have been sequential in
nature. Xhat is, the elements have been located physically one after the other
in memory. Now we will briefly introduce a type of data structure where the
elements may be physically scattered. Xhe individual elements in such a
structure are often called nodes. In such a data structure each element will
contain the address where the next element can be found. Xhis is often
referred to as the link field. If our customer structure were organized this way,
it might look like
NO
NAME
ADDRESS
PHONE
LINK
Node 1
r Node 2
NO
NAME
ADDRESS
PHONE
LINK
• • •
In this case it would no longer be necessary to add 64 to get the next customer.
We need only load the value of the link. Xypically a link value like 0000 could
be used to indicate the end of the list.
One obvious advantage of using a linked structure comes when the in-
dividual structure elements must be arranged in a certain order. For
78
Z-Sfiand 8080 Assembly Language Programming
example, suppose our customer structure is alphabetized by customer name.
(For convenience, only the name field is used.)
Sequential Linked
• ••
Immediately we can see that the linked representation takes more room, but
not much more. An address in an 8080 or Z-80 is two bytes long. So our link
fields will add two bytes to every node. But the nodes were already 64 bytes
long, so as a percentage the increase is not great.
Suppose, though, that we now acquire a new customer named AMBLE.
Using the sequential method, we will have to move every entry down to make
room for the new one. With the linked representation we need only change
ALVARADO's link to point to AMBLE and have AMBLE's Unk point to
AMBROSE.
Available Nodes List
When linked structures are used, it is convenient to keep a separate list of
unused nodes.
Empty
• • •
Then when a new entry is needed, we can take the node from this list.
Similarly, when we wish to delete an existing node from the linked structure,
we can return it to this list to be reused at a later time.
A Casual Introduction to Data Structures
79
Z-80 Block Handling Instructions
The Z-80 instruction set contains eight operations that act on blocks of data.
Whole arrays can be moved or searched using a single command. We will
outline the effects of the instructions and then discuss how these instructions
might influence the way we chose to store arrays using the Z-80.
Z-80 Block Transfer Group
The Z-80 Block transfer instructions make use of three register pairs:
BC: Holds the count telling how many bytes are to be moved.
DE: Points to the destination location to which the next byte will be
moved.
HL: Points to the source location from which the next byte will be fetched.
The load and increment instruction LDI moves one byte from (DE) to
(HL) and then increments both DE and HL and decrements register pair BC.
The dual purpose flag parity/overflow is set if BC /= 0 and it is cleared if BC
= 0. The carry flag is unaffected, but the zero and sign flags are messed up.
The OP code for this instruction is EDA0.
The load, increment, and repeat instruction LDIR performs the same
action as the LDL but continues transferring bytes one by one until the count
in the BC register pair reaches zero. It's OP code is EDB0.
The load and decrement instruction LDD moves one byte from (DE) to
(HL) and then decrements all three register pairs. Flag settings are the same
as for the LDL The OP code is EDA8.
The load, decrement, and repeat instruction LDDR performs the LDD
until the BC pair goes to 0. Its OP code is EDB8.
Z-80 Block Search Group
The Z-80 block search instructions make use of two register pairs and the
accumulator.
A: Holds the value to be searched for.
BC: Holds the count telling how many bytes are to be searched.
HL: Points to the location of the next byte to be searched.
The flag settings for these instructions are all the same.
CARRY: Unaffected.
ZERO: Set if A = (HL). Cleared if A (HL).
PARITY/
OVERFLOW: Setif BC ^ 0. Cleared if BC = 0.
SIGN: Messed up.
80
Z-86 and 8080 Assembly Language Programming
The compare and increment instruction CPI performs a compare
[A — (HL)]; then increments the HL pair and decrements the BC pair. The
OP code is EDM.
The compare, increment, and repeat instruction CPIR performs the
action of the CPI instruction until either BC 9^ 0, or A = (HL). Its OP code is
EDBl.
The compare and decrement instruction CPD performs a compare
[A — (HL)], then decrements both the HL and BC register pairs. The OP code
is EDA9.
The compare, decrement, and repeat instruction CPDR performs the
action of the CPD instruction until either BC = 0 or A = (HL). Its OP code
is EDB9.
Z-80 Array Arrangement
Suppose we are writing a program that requires a large array of two byte
signed variables which are not sorted in any particular order.
HI GARY
IL
IH
2L
2H
3L
3H
2002
2004
2006
Further, suppose that we frequently have to determine whether or not a
certain two byte variable, called TSTVAL, is contained within BIGARY. If
all of these variables were one byte in length, there would be no problem. We
would simply use the search instruction. However, there is no two byte search.
We can still use the built-in search, though, if we split up the array into two
arrays of one byte variables.
Low order
High order
ARYLO
IL
2L
3L
ARYHI
►
IH
2H
3H
•
•
•
We would also conceptually divide TSTVAL into a high and low order byte.
Now we can search just the low order byte for a match with TSTVAL/low. If
we find one, we check the corresponding high order byte for a match with
TSTVAL/high. If they match, we're done, if not, we just go on checking the
low order byte array.
A Casual Introduction to Data Structures
81
Many times it will turn out to be simpler to split the fields of a structure
in this manner as well. In our customer structure, for example, it may be
more convenient to keep several parallel arrays.
CUSTNO
NAME
Exercises
When an array contains a string of characters that is being input or output a
character at a time, it is usually called a buffer. Using the keywords that your
assembler requires to reserve storage, define a buffer large enough to hold 30
characters. Write a subroutine that will accept a string of characters from the
keyboard and place them in successive buffer locations. The input should be
terminated by a carriage return, but do not include that character in the
buffer. Clear any unused buffer locations by inserting the ASCII character for
a space. Do not allow the buffer to overflow. Each character input should be
echoed on the screen or printer.
Write a subroutine which will display a message on the screen or printer. The
routine should be passed a starting location of the message and the number of
characters.
Write a driver routine that calls the subroutines written in exercises 1 and 2
above. It should display the following three questions in turn, and accept a
response for each.
NAME?
ADDRESS?
PHONE NUMBER?
The driver should have storage areas reserved for the answers and should
transfer the information from the buffer after each question. The area
reserved for phone number should be eight characters long. Name and
address may be any suitable length up to 30 characters.
When using a linked structure, the available nodes list keeps the track of
unused nodes. Suppose we have a linked structure where the nodes are 64
bytes long, and where the first two bytes contain the link field.
82
Z-80and 8080 Assembly Language Programming
Reserve an area of storage which is Ik (400^) in length. Force boundary align-
ment so that it begins on an even page boundary.
a. Write a subroutine that will link up all of the storage space into one big
available nodes list. Leave a pointer to the first node in a two byte
variable named AVAIL. The last node should have a zero link value.
b. Write a subroutine that will get a node off from the available list and
return a pointer to it in the HL pair.
Before After
AVAIL
Your routine should check to see if the available nodes list is empty and
should call a routine called OVFLOW if it is.
c. Write a subroutine that will accept a pointer to a node in the HL pair
and return that node to the available nodes list. That is, reverse
"before" and "after" pictures of part b.
binary coded
decimal arithmetic
From previous exercises, vs^e have gained experience v^riting conversion
subroutines that accept as input ASCII characters of digits and produce as
output the binary equivalent of the number. For example, an input in
characters of 1 1 would be converted to a binary 1011, since
Then, if we were to store that number in an eight bit register, it would appear
as
0 0 0 0 1 0 1 1
If we were to store the decimal number 11 in binary coded decimal, however,
it would appear in a register as
0 0 0 1 0 0 0 1
In binary coded decimal arithmetic, each decimal digit is translated into
binary and stored in half a byte (one nibble). So only the following binary
values are used.
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7
1000 = 8
1001 = 9
83
84
Z-80and 8080 Assembly Language Programming
The binary numbers below are not used.
1010 = A
1011 = B
1100 = C
1101 = D
1110 = E
1111 = F
So if we now consider the largest number that will fit in the accumulator, we
see that it is
1 0 0 1 1 0 0 1
= 99
BCD ^^D
Now 99 isn't a very large number, especially in light of financial applications
which use an implied decimal point. If dollars and cents are the units, our 99
becomes 99<f . — this is terribly limiting. Nor does use of a 16 bit register help
much — with it we can only go up to $99.99.
The desired size range for BCD numbers can only be achieved by storing
the numbers in memory and manipulating them in memory as well. Thus, a
BCD number will appear as an array of bytes in memory, each byte con-
taining two digits.
1,256,743.27 =
01
25
67
43
27
Notice that only the digits themselves appear in memory, not the decimal
point. The fact that two digits follow the decimal point will be contained in a
descriptor block which will also give the size of the number in bytes and the
sign of the number, whether positive or negative.
Decimal Adjust Instruction
Suppose we decided to add two BCD numbers. For convenience, let's suppose
each number is exactly two digits long.
19
+ 23
42
Now let's see what we would get in the accumulator if we performed addition
on these two numbers in BCD.
Binary Coded Decimal Arithmetic
85
0 0 0 110 0 1
+ 0 0 1 0 0 0 1 1
0 0 11
110 0
= 3C
Whoops! The result of this addition left us with one of the unused binary
numbers, namely C = 1100. So we added two BCD numbers, but the result
was not a BCD number.
We would have a similar problem upon performing the following
subtraction:
57
- 19
38
0 10 10 111
1110 0 110
0 0 111110
3E
So how can we add or subtract BCD numbers? The answer comes in the form
of an additional instruction. The decimal adjust instruction DAA, OP code
27, takes a result in the accumulator, such as the 3C from the above addition,
and automatically corrects it to the value 42. The same instruction also
corrects the outcome of a subtraction operation.
Multi-byte addition and subtraction algorithms will be given later. Now
that we know we can successfully add and subtract BCD numbers, let us turn
our attention to conversions between character and BCD forms of the
numbers.
Input and Output of BCD Numbers
We know that BCD numbers will be stored in memory with two digits per
byte, but the same numbers will be input and output in character form. For
example, if the number 1234 were input from the keyboard it would appear
in the input buffer in character form. Then it would have to be "packed" into
BCD form as illustrated below.
31
32
33
34
12
34
Similarly, on output, conversion would have to go the other way.
.56 78 .
35
36
37
38
86
Z-80and 8086 Assembly Language Programming
Let's consider how this conversion might be done. From character to
BCD
1 . Load the first digit into the accumulator. A| 0 0 1 l|0 0 0 1
A
= 31
H
2. Subtract 30^.
3. Rotate the accumulator four times to
the left.
00000001= 01
0 0 0 1 0 0 0 0
= 10
H
4. Save this value in a temporary storage B00010000
location.
5. Load the second digit into the
accumulator.
6. Subtract 30,
'H'
A
A
0 0 1 1 1 0 0 1 0| = 32h
02
0 0 0 0 0 1 0
H
0 0 0 010 0 1 0
7. Add in the value from the temporary
storage location.
8 . Save the result as the first byte of the +B | 0 0 0 f 0 0 0 0
BCD number.
02
H
= 10
H
0 0 0 1 0 0 1 01 = 12h
The above steps would be repeated for each pair of characters input.
Converting from BCD to character
1 . Load the first byte of the BCD
number into the accumulator.
2. Perform an "AND" operation with
0 1 0 1 0 1 1 0 = 56
H
a mask whose value is F0
H-
A
AND mask
1 0 1 0 1 1 0 = 56
H
1111
0 0 0 0 = F0
'H
0 1 0 1 0 0 0 0
= 50
H
3. Rotate the accumulator to the
right four times.
0 0 0 0 0 1 0 1
= 05
H
4. Add in 30
H
0 0 110 101
= 35
H
5. Output the result as the first
digit in character form.
6. Load the first byte of the BCD
number into the accumulator again.
7. Perform an "AND" operation
0 10 10 110
= 56
H
A 0 1 0 1 0 1 1 0
= 56
H
with a mask whose value is 0Fj^.
AND mask 0 0 0 0
1111
= 0F
H
0 0 0 0 0 1 1 0
= 06
H
8. Add 30 and output the result
as the second character of the result.
0 0 110 110
= 36
H
Binary Coded Decimal Arithmetic
87
Again, all eight steps would have to be repeated for each pair of characters
output.
RLD and RRD in Character-BCD Conversions
The 8080 programmer has no choice but to use the above algorithm or one
equivalent to it. The Z-80 programmer can make use of the RLD and RRD
instructions to simplify the conversion routines. These two instructions have
been discussed before, but they are diagrammed again here for reference.
(HL)
1 A 1
1
1
«
+ 1
"■ 1
i i
f-- i
' r-'
(HL)
1
L i
RLD
RRD
Let's trace how the algorithms would go using these instructions for
conversion from character to BCD. Assume the following register pairs are
used as pointers.
HL: points to the first character in the input buffer
DE: points to the first byte of the BCD
1 . Clear the accumulator and RRD the first digit into the accumulator.
00., A 1000 0| 000 l|= 01
00000000
H
H
(HL) 1 0 0 1 1 I 0 0 0 31h (HL) I 0 0 0 0| 0 0 1 l| = 03^
Before After
2. Store the contents of the accumulator into the location pointed to by the
DE pair.
3. Increment the HL pair to point to the next character, and repeat step 1 .
0 0 0 0 0 0 1 0
4. Now exchange the contents of the DE and HL registers (DE-^ — ^ HL)
so the HL pair points to the first byte of the BCD number. Then RLD
second digit into the byte.
' ' ' = 00
0 0 0 0 0 0 1 0
= 02
H
00000000
H
(HL) |0 0 0 0|0 0 0 1 I = OIh (HL) |0 0 0 1 I 0 0 1 0| = 12^
Before After
These four steps can then be repeated for each pair of digits input.
88
Z-80 and 8080 Assembly Language Programming
Storing the BCD Number in Memory
We have aheady stated that a BCD number generally occupies several bytes
and requires some type of descriptor block telling
1 . size
2 . number of digits to the right of the decimal point
3. sign
The method presented below is by no means the only possible way to store this
information. Its main advantage is simplicity. The maximum size of the
number to be dealt with is completely up to the programmer and will depend
on the application. The storage area to be reserved, however, will be three
bytes larger than the space required to hold the longest possible number.
Those thcee bytes will then hold the descriptor data for the number.
1234.56
would appear in memory as
06
02
12
34
56
The number is 6 digits long,
two digits to the right of the decimal point, and
the number is positive (01^ indicates negative).
This is the number itself.
Alignment of the BCD Number
We have still not completely characterized the BCD number. Suppose the
following number is input.
123.45
This number has five digits in it, and we pack two to a byte, so there will be an
odd digit left over. Should we store the number as
_01_
23
45
or
12
34
50
The first method will turn out to be the simplest to deal with, because in this
representation the decimal point lies between two bytes and not in the middle
of a byte. This will turn out to be extremely useful in addition and subtraction
Binary Coded Decimal Arithmetic
89
of numbers with decimal points in different places. In fact, we will make it a
rule always to have the decimal point on a byte boundary.
123.456
would appear in memory as
01
23
45
60
But now what should we put in the descriptor block? We have just
changed both the number of digits in the number and the number to the right
of the decimal point. The answer is that we will want to use the descriptor
block to tell us the total number of bytes to the right of the decimal point.
Number of bytes
in number
Number of bytes
to the right
of the decimal
point
Sign
Value
Now what about our input routines? We designed them as though the
number would simply be read from left to right in the buffer. Now we want to
work outward from the decimal point in both directions. Does this mean the
whole set of routines will have to be discarded? Fortunately, this will not be
necessary if we are careful in the design of our data areas. The algorithm to
be used will be outlined, but at this time let us also discuss how to set up the
descriptive block and how to deal with extraneous character inputs such as ","
or . or + .
We will begin by allowing an extra byte of storage whose value is 30^^.
This byte will be located just before the buffer area.
SPARE: .BYTE 30^
BUFFER: BLKB 120
SPRFLG: BLKB 1
NUMBER: BLKB 65
90
Z-86 and 8080 Assembly Language Programming
We will then assume that the number is input into the buffer area beginning
at BUFFER + 0. Examination of the buffer contents will thus begin at that
address. Each character in the buffer will be examined in turn.
Initialization: Zero the space flag (SPRFLG) and the entire data area
reserved for NUMBER. Set the HL and DE register pairs so that both point to
BUFFER + 0. Zero registers B + C to be used for counts.
Presignificance loop (repeat 1 and 2 until a jump out of the loop oc-
curs ) :
1 . Fetch a character from the buffer location pointed to by the DE pair.
2. Test for one of the following and perform the corresponding action
upon a match:
a. Space — Increment the DE register pair.
I
+
b. — — Move a 1 to the sign descriptor byte. Increment the DE register
pair.
c. . — Increment the DE register pair and jump to the post-decimal loop.
d. Digit — Move the character to the location pointed to by the HL pair.
(0-9) Increment both the DE and -HL registers. Increment the B
register. Jump to the post-significance loop.
e. Any — Jump to the termination segment,
other
Post-significance loop (repeat 1 and 2 until a jump out of the loop oc-
curs):
1 . Fetch a character from the buffer location pointed to by the DE pair.
2. Test for one of the following and perform the corresponding action
upon a match:
a. , — Increment the DE register pair.
b. — — - Move a 1 to the sign desciptor byte. Jump to the termination
segment.
c. . — Increment the DE register pair and jump to the post-decimal
loop.
d. Digit — Move the character to the location pointed to by the HL pair.
(0-9) Increment both the DE and HL registers. Increment the B
register.
e. Any — Jump to the termination segment,
other
Post-decimal loop (perform 1 and then repeat 2 and 3 until a jump
out of the loop occurs):
L Check the digit count in register B. If it is an odd number (bit 0 is set),
increment register B and set the spare flag (SPRFLG "^1).
2. Fetch a character from the buffer location pointed to by the DE pair.
Binary Coded Decimal Arithmetic
91
3. Test for one of the following and perform the corresponding action
upon a match:
a. — — Move a 1 to the sign descriptor byte. Jump to the termination
segment.
b. Digit — Move the character to the location pointed to by the HL pair.
(0-9) Increment both the DE and HL registers. Increment both the B
and C registers.
c. Any — Jump to the termination segment,
other
Termination segment:
1. Check the digit count in register B. If it is an odd number (bit 0 is set)
increment both the B & C registers and move the value 30^ to the
location pointed to by the HL pair.
2. Divide the contents of register B by 2 by shifting to the right and store
this value in size.
3. Repeat for register C, store in number of digits to the right of the
decimal point.
4. Set the HL register pair to point to
a. BUFFER + 0 - if SPRFLG = 0
b. SPARE - if SPRFLG = 1
5. Use the previously described translation routine to convert the input
characters to BCD. The number of repetitions for the loop is the value
in SIZE.
Although this routine may seem to be long and complex, it is really
worth the effort to encode and debug it. Once written, it becomes a highly
portable utility routine that can be used in any application requiring BCD
arithmetic.
Fixed Point Addition and Subtraction
We have already seen how the use of the decimal adjust instruction DAA can
greatly simplify addition and subtraction of BCD numbers. Now it is time to
consider the subleties of decimal point alignment and discuss how a BCD
routine to add and subtract fixed point numbers might be structured.
First consider the following addition operation.
1.023 + 7.7
A routine that performs this addition must take into account the need to
properly align the decimal point.
1.023
+ 7.7
8.723
92
Z-80 and 8080 Assembly Language Programming
It is also necessary to decide on the location for the result of the operation. If
it is decided to leave the result in either the first or the second operands, the
fact that the result may be larger than the inputs must be taken into account
in the algorithm design. Lastly, the routines must take into account the sign
of the inputs, since the numbers themselves are not stored in any fashion such
as 2's complement v^hich allows them to be dealt with directly.
The routines described below will extend zeroes to the right of the
decimal point of the shorter number to solve the alignment problem. For
example,
1.023 + 7.7
will become
1.023
+ 7.700
8.723
The location of the result will be a totally separate result area. This area will
act as a buffer in the sense that a second call to the addition routine will
destroy the result of the previous addition. So the calling program will have to
move the result to the location of its choice.
The sign of the inputs will be taken into account in the following
manner.
Addition:
Operands of the same sign: Perform addition on the two
operands. Attach their common
sign to the result.
Operands of opposite sign: Subtract the smaller from the
larger. Attach the sign of the
larger to the result.
Subtraction:
Given operand 1 minus operand 2, change the sign of operand 2 and
add. Restore the sign of operand 2 before returning from the
subroutine.
The whole subject of attaching the proper sign to the result apparently
depends on the ability to compare two BCD numbers. Since these numbers
can be extremely long, such a comparison may seem difficult. In fact, it is not
terribly hard to do this. Before a comparison is made, the two numbers will
first be adjusted so they have the same number of bytes to the right of the
If
Binary Coded Decimal Arithmetic
93
decimal point. At this time the size of the two numbers can be compared. If
one is longer, it is larger. Numbers of the same length can be subjected to a
byte-by-byte unsigned compare.
The routines themselves make use of two length indicators. These are the
lengths of the two operands after decimal point adjustment has taken place.
The basic loops merely involve a straight add (or subtract) of the lowest order
byte and an add (or subtract) with carry of every higher order byte until the
shorter number is exhausted. After that point has been reached, the routine
continues to add (or subtract) with carry using a "dummy" operand with a
zero value until the longer number is exhausted. After each and every ad-
dition (or subtraction) the decimal adjust operation is performed.
Floating Point Multiplication
The method to be used in floating point multiplication parallels that used in
long-hand computation.
7.032
X .42
14064
28128
2.95344
The size of the result will be, at most, the sum of the sizes of the two operands.
The number of bytes to the right of the decimal point will be exactly the sum
of the numbers of bytes to the right of the decimal point in the two operands.
To outline the method to be used, consider the two BCD operands as
strings in memory. The smaller operand will be used as the multiplier and
will have a pointer to its least significant digit's byte
Multiplicand
Multiplier
Least significant digit
The digit in the multiplier will be read, and the multiplicand will be
added into the result that many times. The addition will ignore the decimal
point in the multiplicand. Then the multiplicand will be shifted to the left
four bits (i.e., multiplied by 10), and the next digit in the multiplier will be
considered. This process will be repeated until all of the digits of the
multiplier have been used up. In the process of left shifting the multiplicand,
the RLD instruction will prove invaluable.
94
Z-Sfiand 8080 Assembly Language Programming
The sign of the resulting product can easily be determined by comparing the
signs of the operands:
Operands Result
+ + +
+ -
- +
- - +
Floating Point Division
Again the technique utilized will parallel that used in long division. To trace
the method, however, we will have to analyze the thought processes used in
division very carefully. Consider first the approach taken in performing the
following long division.
6.347 I 10.4
The first step in performing this division by hand would be to shift the
decimal point three places to the right in both the divisor and the dividend.
6.347. I 10.400. = 6347 I 10400.
Once this step has been performed, the decimal point is fixed in the result.
But in our algorithm it will be the number of bytes to the left of the decimal
point that we will want to keep track of, since the number of bytes to the right
will depend on the accuracy with which the calculation is performed. The
desired number of bytes of accuracy would have to be input to the subroutine
as a parameter.
An outline of the algorithm follows.
1 . Check the number of bytes to the right of the decimal point in the
divisor. If this is nonzero, multiply both dividend and divisor by 100 by using
an eighth bit left shift. Repeat this step until the divisor has no digits to the
right of the decimal point. The eight bit shift can be accomplished by simply
adding the digits 00 to the end of the number and adjusting the decimal
point.
2. Subtract the number of bytes to the right of the decimal point from
the total number of bytes to obtain the number of bytes to the left of the
decimal point in the dividend.
3. Now create the quotient by performing the following loop the number
of times equal to the desired accuracy as input. Note that using this system
leading zeroes will be counted as digits of accuracy. The number of bytes of
accuracy would be obtained by adding to the end of the dividend the required
number of 00 bytes to make its total length equal to the desired accuracy.
Begin the loop by left shifting the dividend four bits and taking only the first
byte as the assumed size of the dividend.
Binary Coded Decimal Arithmetic
95
a. Subtract the divisor from the assumed size of the dividend. Keeping a
count of the number of subtractions performed, repeat until the result
goes negative. At that point, add the divisor back and decrement the
subtraction count. Output the count as a digit of the quotient.
b. Left shift the dividend four bits, but maintain the same assumed size of
the dividend. Repeat step a.
c. Left shift the dividend four bits and increase the assumed size of the
dividend by one byte. Repeat steps a-c until the desired number of bytes
of accuracy have been obtained.
4. When the entire quotient has been formed, delete leading 00 bytes
and adjust the decimal point accordingly.
Exercises
1 . Write a subroutine which will take as input a number in character form in a
buffer and produce as output the BCD value of the number.
2. Write a subroutine which will perform a fixed point addition of two BCD
numbers.
3. Write a subroutine which will perform a fixed point subtraction of two BCD
numbers.
4. Write a subroutine which will perform a floating point multiplication of two
BCD numbers.
5. Write a subroutine which will perform a floating point division of two BCD
numbers.
when time is important
In this chapter we will be dealing with two totally separate types of time. On
the one hand, we will discuss how to optimize program development time
That is, how to get the most from the human hours that go into program
design, coding, testing, and debugging. On the other hand, we will consider
how to minimize machine execution time in applications where run speed is
critical.
An Approach to Program Development
George has just been given a job contract to develop a complete
microcomputer program for a talent agency. He talks to the owner and she
spends an hour and half telling him all the things she wants the program to
do. The task seems frightening, but he will make enough money to pay for his
complete computer system five times over.
At home, perched at his desk and ready to work, he drags out all the
notes he took at his interview. The first thing he will want to do is ('i^ begin
with a clear idea of what the program is to accomplish. George determines
that the talent agency wants the program to maintain a complete, up-to-date
file containing name, address, phone number, and abilities profile for each of
its clients. The agency would like to give an casting director an immediate yes
or no answer as to whether they have a client on file with a given abilities
profile. If the director wants to make an interview appointment, the agency
will need to get a display of the names, addresses, and phone numbers of all
clients who fit the profile. With the total task summarized, George's thoughts
are already turning to the second step: (2) divide the total task into any
isolatable sub-tasks.
He can identify three clearly distinguishable sub-tasks in the talent
agency program:
a. keeping the client file current
b. performing a search for a given profile
c. listing name, address, phone on matches
Now George is really clicking, ideas are starting to pour in. He jots dovm on
scratch paper a few ideas he doesn't want to forget. For instance, the thought
96
When Time Is Important
97
just occurred to him that all the information the agency needs to know about
its people can be contained in a single byte. But George doesn't get carried
away from his planning. He moves right into the third step: (3) concentrating
on a single one of the sub-tasks, repeat step 2. Repeat 2 and 3 until all of the
program modules have been designed.
George zeroes in on the problem of keeping the client file current. He
divides it as follows.
A. adding new clients and their profiles
B. updating a field in a client record
C. deleting former clients and their profiles
The problem of adding new clients and their profiles becomes the next series
of tasks.
i. getting a new node area
ii. filling in name, address, and phone fields
iii. collecting employee profile information and organizing it into a descrip-
tive byte
Getting a new node is no problem. George can easily adapt a subroutine he
wrote long ago to do this. Filling in name, address, and phone fields he had
also done before. George has a collection of message input and output
subroutines to draw on. So the only problem George faces right now is
collecting and organizing profile information. Deeply absorbed in his work,
George has completely forgotten how awesome the task appeared at first. The
profile task still needs narrowing down. He refers to his notes and decides that
he can use his standard I/O subroutines to collect the answers to a series of
questions. He'll convert a yes to a 1 and a no to a 0. Going into the routine
he'll clear the accumulator. Then he'll set the low order bit accordingly and
shift one to the left before the next question.
Before too long, and well before the design deadline, George has the
complete program design. He knows what his data will look like in memory.
He knows what routines and subroutines are needed for the job and has a
good idea of what machine capabilities he will utilize in the performance of
each task. He has a complete block diagram of his program showing which
routines call what subroutines. A portion of George's block diagram is shown
on the following page.
Through all this design effort, George has not written a single line of
assembly language code. With the design complete, though, he's ready to
begin coding. It's no haphazard guess as to what to code first. George is
following the fourth step: (4) code the main driver first, then all first level
subroutines and so on, coding from the top doxvn to the lowest level
subroutine. Coding takes a long time. A few problems arise for George, but
he discovers that even though he has to adjust his design a little, he never
98
Z-80 and 8680 Assembly Language Programming
seems to have to make many changes to code he has already written. That's
the top-down approach working for him. If he'd begun coding from the
lowest level subroutine up, he would be spending half his time erasing code
and tracking down the repercussions of minor changes.
mam
program
driver
update
driver
search
for
profile
listing
matches
client
addition
record
change
client
deletion
get
node
name/
address
phone
client
profile
output
message
input
message
output
message
input
message
George is doing more than just writing code right now. He is
documenting every routine he writes. Long ago he formed the habit of
commenting every line of assembly code. SET 5,D won't give you any clues as
to what you were up to when you wrote it two weeks ago. But line comments
aren't enough for a project of this size. George keeps a whole block of com-
ments as a header to each subroutine. He always includes
NAME:
FUNCTION:
CALLED BY:
CALLS:
ARGUMENTS:
The complete name of the routine with acronyms
expanded in full.
A brief description of the purpose of the routine.
The names of all the routines that call this routine.
The names of all the routines that this routine calls.
Any data that is passed to this routine in a register
or returned from this routine in a register is clearly
spelled out.
When Time Is Important
99
George never omits any of these items. For instance, in his main program
driver he has the Hne
CALLED BY: NONE
Then he knows that no item was forgotten. George also carefully documents
the data structures he is using. The name, the size, the function, and the
alignment of all variables and tables are included.
Finally the job of coding is finished and George surveys the job with
satisfaction. The program fills a three ring binder. He has sections separated
by dividers for all his documentation and for each subroutine. Now he is
ready to begin to assemble the code and test it. George is quite excited about
the project. He's itching to enter all the code, assemble it, and let it rip. But
he knows that method would only give him a big letdown. Even the smallest
subroutine isn't guaranteed to run the first time. It has to be debugged, and
with a project of any size, that can be either a nightmare or a smooth, orderly
procedure, depending on the way it is approached. So George won't let his
enthusiasm run away with him. Instead he'll follow the fifth step: (5) assemble
and test the lowest level subroutines first, working from the bottom up.
George begins with the utility routines he's adapting from previous
programs. His basic I/O routines really get the once-over. Every time George
tests a routine, he uses the same basic plan. He is always careful to include test
cases that will exercise every branch. He wants to be sure that every line of
code is executed during the test phase. When he feels confident that the
jumps are jumping properly and the loops are looping, George is still not
ready to certify the routine as fully debugged. What if bad data comes
through? What if a clerk types a name where a number should have been
entered? Will the whole program come to a crashing halt? George has in-
cluded data validation checks in his subroutine designs wherever a problem
could cause a crash. Now, during debug, he will try out the weirdest of the
weird data inputs to see what effects they have on the system. If an empty
array is passed, will the loop droop? If the program runs out of space for more
clients, will it.ignore the problem and wipe out anything in its way?
If George discovers that he's done a "jump on zero " when he wanted a
"jump on a nonzero " or some such error, he can alter the program.
LOG 204E = CA 4323 (jump on zero to 2343)
George can simply change one instruction by TE at 204E to a D2, so
LOG 204E = D24323 (jump on nonzero)
Such changes are very simple when the corrected instruction is the same
length as the original instruction.
If George discovers that he's got an instruction in the program that he
doesn't want, he can just substitute NOP instructions in its place. For
example, to remove
100
Z-Sdand 8080 Assembly Language Programming
LOC214B = CD3750 (call loc. 5037)
replace it with three NOPs:
LOC 214B = 00
214C = 00
214D = 00
Now what if George discovers he's forgotten an instruction that should be
there? He could stop his debugging in midstream while he corrects the
program and reassembles, or he could simply make a "patch." A patch is a
program repair that involves making an unconditional jump out to an unused
location in memory (called the patch area). There, any omitted instructions
can be hand assembled and listed directly in machine code before making an
unconditional jump back to program area. There are four steps involved.
1 . Create a jump out to the patch area "C3 " by replacing three bytes
in the program. [If you replace only part of an instruction, be sure to
replace the rest of it with NOP(s).]
2. In the patch area replace the instruction(s) removed for the jump.
3. Enter the missing instruction(s) in machine code.
4. Code a jump back to the program area at the end of the patch.
A patch log which shows all changes to the program made during debug can
prove to be invaluable.
Only when he's convinced that the routine is uncrashable does George
certify it complete and go on to the next. As new routines are debugged, they
are combined with the previous ones, gradually building toward the complete
system. When at last the day comes that the driver takes off and drives,
George knows he's got a winner. He takes a well-earned couple of days off
before the final work on the system.
Yes, there's more. George wants to be sure the program will work under
field conditions, so he copies names from the phone book and invents profiles
randomly until he has as many "clients" on his system as the agency will have.
Will searches slow to unbearable waits under a heavy load? Will an agency
clerk give a yes to a casting director only to discover that there's only one
client with that profile, and his address and phone number are garbled?
George needs to know the answers. Can he do the search if a director says, "I
don't care if it's a man, woman, or goat — just send me someone who can act!"
Fortunately, George did his work well and his system responds gracefully
to the most outlandish inputs. It's time for a party! But soon after, he's back to
work. Still? Yes, George has to write his user documentation. Complete, clear,
easy-to-follow directions must be prepared for each type of entry or inquiry to
the system. George doesn't assume any knowledge on the part of the operator.
He makes the documentation complete enough for the first-time user, but at
When Time Is Important
101
the same time, concise enough to provide quick reference for the experienced
user.
Needless to say, now that George has delivered the completed system to
the talent agency, he feels confident that it will serve them well. And George
. . . well, he's vacationing in Bermuda.
Optimizing Run Time
It is in pursuit of speed that most programmers turn to assembly language
code. The interpretive nature of BASIC slows execution to the point where
complex programs run at an intolerably slow pace. For most applications,
merely switching to assembly language provides the needed speed up. Oc-
casionally, however, the application is so demanding and so time-critical that
the use of assembly code in itself is not enough. In such applications it is
necessary to identify those segments of code which must be executed
repeatedly within a short time frame, perhaps thousands of repetitions must
be made within a minute or so. Once the real bottlenecks have been isolated,
these routines can be optimized.
Optimization of code requires an awareness of the time the computer
spends in executing a particular type of instruction. The time is not so much
the absolute time required for each, but more important, is the relative
execution times of the various instructions. We will measure relative
execution times in terms of a "T-state." A T-state corresponds to a single
clock pulse in the central processing unit. The actual time required for a T-
state depends on the clock speed of the individual microprecessor. For in-
stance, if the microprocessor is running at 1 MHz (one megahertz), then there
are one million T-states per second. A 4 MHz clock rate produces four million
T-states per second.
When trying to decide whether optimization is worthwhile, remember
that T-states must be saved by the millions to cut seconds off execution time.
The instruction times for each instruction as measured in T-states are
included in the instruction summary appendix. The execution times fall into
basic groups depending on the location of the operands. The fastest type of
instruction, for instance, operates on two operands which are both located in
eight bit registers. The chart on page 102 summarizes the instruction times
for eight bit operands based on operand location.
Here we see the characteristic longer execution times for the indexed
instructions which typically take 2.5 to nearly 6 times longer than the
corresponding instruction in an eight bit register. To show how optimization
can take place, suppose the code you were trying to speed up used an indexed
storage location to hold a temporary result in a computation. To put the
value out in memory would require 19 T-states. To retrieve it, another 19, for
a total of 38. Saving the same value in an eight bit register takes four T-states
102
Z-8d and 808d Assembly Language Programming
and four to retrieve it, for a total cost of eight T-states. If that register is free,
we've found a way to save 30 T-states.
Operation
r
(HL)
n
(lY + d)
(IX + d)
(nn)
LOAD
ADD
SUBTRACT
AND
OR
XOR
COMPARE
4
7
7
19
13*
INCREMENT
DECREMENT
4
11
23
ROTATE
SHIFT
SET BIT
RESET BIT
8t
4
15
23
BIT TEST
8
12
20
♦LOAD only.
fExcept accumulator.
Exercise
1. As a programmer, you have now had numerous examples of code written by
and for you. You should by now have investigated the I/O techniques used in
your monitor and learned the key words your assembler needs to see to locate
a program at a fixed spot in memory and to reserve and name storage
locations. If you have not already done so, it's time to learn how to create a
text file on your system and how to assemble and load a program. We have
just finished discussing techniques for organizing an approach to large
programming projects. In short, you should now have all the tools necessary
to tackle a programming project of your own design.
APPENDIX A
8(3O0/ZILOG MNEMONICS CONVERSION
SYMBOLS USED
SYMBOL OPERATION
r one of the 8-bit registers A,B,C,D,E,H,L
n any 8-bit absolute value
ii an index register reference, either X or Y
d an 8-bit index displacement, where -128< d< 127
zz B for the BC register pair, D for the DE pair
nn any 16-bit value, absolute or relocatable
rr B for the BC register pair, D for the DE pair, H for the HL pair,
SP for the stack pointer
qq B for the BC register pair, D for the DE pair, H for the HL pair,
rSW for the A/Flag pair
s any of r (defined above), M, or d(ii)
IFF Interrupt flip-flop
CY carry flip-flop
ZF zero flag
tt B for the BC register pair, D for the DE pair, SP for the stack
pointer, X for index register IX
uu B for the BC register pair, D for the DE pair, SP for the stack
pointer, Y for index register lY
b a bit position in an 8-blt byte, where the bits are numbered from
right to left 0 to 7
PC program counter
b{n} bit n of the 8-blt value or register v
w/H the most significant byte of the 16-bit value or register w
w/L the least significant byte of the 16-blt value or register w
Iv an input operation on port v
Ov an output operation on port v
w V the value of w is replaced by the value of v
w V the value of w is exchanged with the value of v
103
8 BIT LOAD GROUP
8080
MNEMONIC
MOV r,r'
MOV r,M
MOV r,d(ii)
MOV M,r
MOV d(il),r
MVI r.n
MVI M,n
MVI d(ii),n
LDA nn
STA nn
LDAX zz
STAX zz
LDA I
LDAR
STAI
STAR
OPERATION
r ^ r'
r ^ (HL)
r ^ (il+d)
(HL) -<- r
(il+d) r
r -<- n
(HL) -f- n
(li+d) ^ n
A (nn)
(nn) *- A
A (zz)
(zz) A
A ^ I
A ^ R
I ^ A
R ^ A
ZILOG // OF // OF
MNEMONIC BYTES T STATES
LD r,r' 1 4
LD r,(HL) 1 7
LD r/Iil+d) 3 19
LD (HL),r 1 7
LD (Ili+d),r 3 19
LD r,n 2 7
LD (HL),n 2 10
LD (Iil4tl),n 4 19
LD A,(nn) 3 13
LD (nn),A 3 13
LD A,(zz) 1 7
LD (zz),A 1 7
LD A,I 2 9
LD A,R 2 9
LD I,A 2 9
LD R,A 2 9
16 BIT LOAD GROUP
8080
MNEMONIC
LXI rr , nn
LXI 11, nn
LBCD nn
LDED nn
LHLD nn
LIXD nn
OPERATION
rr nn
11 ■<- nn
B ^ (nn+1)
C (nn)
D *- (nn+1)
E ^ (nn)
H *- (nn+1)
L (nn)
IX/H (nn+1)
IX/L ^ (nn)
ZILOG
MNEMONIC
LD rr,nn
LD 11, nn
LD EC, (nn)
LD DE, (nn)
LD HL, (nn)
LD IX, (nn)
if OF
BYTES
3
4
4
// OF
T STATES
1«)
14
20
20
16
20
104
LIYD nn
lY/H
lY/L ^
(nn+1)
(nn)
LD IY,(nn)
4
20
LSPD nn
SP/H
SP/L ^
(nn+1)
(nn)
LD SP,(nn)
4
20
SBCD nn
(nn+1)
(nn)
^ B
^ C
LD (nn),BC
4
20
SDED nn
(nn+1)
(nn)
D
■>- E
LD (nn),DE
4
20
SHLD nn
(nn+1)
(nn)
H
L
LD (nn),HL
3
16
SIXD nn
(nn+1)
(nn)
IX/H
IX/L
LD (nn),IX
4
20
SIYD nn
(nn+1)
(nn)
lY/H
^ lY/L
LD (nn),IY
4
20
SSPD nn
(nnfl)
(nn)
SP/H
SP/L
LD (nn),SP
4
20
SPHL
SP ^ HL
LD SP,HL
1
6
SPIX
SP ^ IX
LD SP,IX
2
10
SPIY
SP ^ lY
LD SP.IY
2
10
PUSH qq
(SP-1)
(SP-2)
SP
- qq/H
^ qq/L
SP-2
PUSH qq
1
11
PUSH li
(SP-1)
(SP-2)
SP
■«- li/H
^ li/L
SP-2
PUSH 11
2
15
POP nn
qq/H *
qq/L ^
SP ^
(SP-1)
(SP)
SP-2
POP nn
1
10
POP 11
li/H
11/L
SP
(SP+1)
(SP)
SP+2
POP 11
2
14
EXCHANGE, BLOCK TRANSFER, AND SEARCH GROUP
8080 ZILOG 9 OF # OF
MNEMONIC OPERATION MNEMONIC BYTES T STATES
XCHG HL <-*-l)E EX DE,HL 1 4
EXAF PSW *-^PSW' EX AF,AF' 1 4
EXX BCDEHL ---^BCDEHL' EXX 1 4
105
H ^(SP+1) EX (SP) ,HL
L -(->-(SP)
IX/H ^(SP+1) EX (SP),IX
IX/L ^(SP)
lY/H ^(SP+1) EX (SP),IY
lY/L ^(SP)
(DE) ^ (HL) LDI
DE <- DE+1
HL ■<- HL+1
BC ^ BC-1
repeat LDI until BC=0 LDIR
(DE) * (HL) LDD
DE ^ DE-1
HL HL-1
BC ^ BC-1
repeat LDD until BC=0 LDDR
A - (HL) CPI
HL *■ HL+1
BC 1- BC-1
repeat CCI until A=(HL) CPIR
or BC=0
A - (HL) CPD
HL *■ HL-1
BC BC-1
repeat CCD until A=(HL) CPDR
or BC=0
2
2
2
2
19
23
23
16
21/16
16
21/16
16
21/16
16
21/16
8 BIT ARITHMETIC AND LOGICAL
OPERATION
A ^ A + r
A A + (HL)
A A + (ii+d)
A A + n
A ^ A + s + CY
ZILOG
MNEMONIC
ADD A,r
ADD A,(HL)
ADD A, (Ill+d)
ADD A,n
ADC A,s
# OF // OF
BYTES T STATES
1 4
1 7
3 19
2 7
As shovm for ADD
instruction
A ^ A + n + CY
A +- A - s
ADC A,n
SUB s
106
SUI n
SBB s
SBI n
ANA s
ANI n
ORA s
ORI n
XRA s
XRI n
QIP s
CPI n
INR r
INR M
INR d(il)
DCR r
DCR M
DCR d(li)
A ^ A - n
A ^ A - s - CY
A ^ A - n - CY
A A A s
A ^ A A n
A
A
A
A
A
A
A V s
A V n
3
A n
- s
- n
r r + 1
(HL) *- (HL) + 1
(11+d) ^ (li+d) + 1
r r - 1
(HL) *- (HL) - 1
(il+d) ^ (il+d) - 1
SUB n
SBC A,s
SBC A,n
AND s
AND n
OR s
OR n
XOR s
XOR n
CP s
CP n
INC r
INC (HL)
INC (lil+d)
DEC r
DEC (HL)
DEC (lii+d)
GENERAL PURPOSE ARITHMETIC AND CONTROL GROUP
8080
MNEMONIC
DAA
CMA
NEC
CMC
SIC
NOP
HLT
DI
EI
OPERATION
convert A to packed BCD
after an add or subtract
of packed BCD operands
A
A
■^A
-A
CY m:y
CY 1
no operation
halt
IFF *- t)
IFF *- 1
ZILOG
MNEMONIC
DAA
GPL
NEC
CCF
SCF
NOP
HALT
DI
EI
// OF
BYTES
// OF
T STATES
1
2
1
1
1
1
1
1
4
8
4
4
4
4
4
107
IM0
IMl
IM2
Interrupt mode 0
interrupt mode 1
Interrupt mode 2
IM 0
IM 1
IM 2
2
2
2
8
8
8
16 BIT ARITHMETIC GROUP
8080
MNEJ^ONIC
DAD rr
DADC rr
DSBC rr
DADX tt
DADY uu
INX rr
INX li
DCX rr
DCX 11
OPERATION
HL ^ HL + rr
HL HL + rr + CY
HL HL - rr - CY
IX IX + tt
lY ^ lY + uu
rr rr + 1
11 ^ 11 + 1
rr -<- rr - I
11 ^ 11 - 1
ZILOG
MNEMONIC
ADD HL.rr
ADC HL.rr
SBC HL.rr
ADD IX, tt
ADD IY,uu
INC rr
INC 11
DEC rr
DEC 11
// OF
BYTES
1
2
2
2
2
1
2
1
2
if OF
T STATES
11
15
15
15
15
6
10
6
10
ROTATE AND SHIFT GROUP
8080
MNEMONIC
RLC
OPERATION
A
ZILOG
MNEMONIC
RLCA
// OF
BYTES
# OF
T STATES
RAL
CY ^ 7 ^ 0
1
RLA
RRC
L|7 * 0lJv
0}Jv[cy]
RRCA
RAR
c
7^0
CY
i]
RRA
RLCR r
RLCR M
RLCR d(ii)
Same diagram as
for RLC
RLC r
RLC (HL)
RLC (Ill+d)
2
4
8
15
23
108
RALR s
RRCR s
RARR 8
SLAR s
Same diagram as
for RAL
Same diagram as
for RRC
Same diagram as
for RAR
CY
0^0
RL s
RRC s
RR s
SLA s
Same as for RLCR
instruction
SRAR s
SRLR s
RLD
RRD
0 ■> CY
0-» I 7 -» 0 I I CY
s
A 17 4l3 0
(HL) l7 4l3 0
tzzr
A 17 4l3 0
r
(HL) |7 413 0
SRA s
SRL s
RLD
RRD
L-ZJ
BIT SET, RESET, AND TEST GROUP
18
18
8080
MNEMONIC
OPERATION
ZILOG
MNEMONIC
// OF
BYTES
// OF
T STATES
BIT b,r
ZF ■<- 'vr{b}
BIT b,r
2
8
BIT b,M
ZF + %(HL){b}
BIT b,(HL)
2
12
BIT b,d(li)
ZF ^ -x-dll-fdXb}
BIT b,(Iil+d)
4
20
SET b,r
r{b}-^ 1
SET b,r
2
8
SET b,m
(HL){b} ^ 1
SET b,(HL)
2
15
SET b,d(ll)
(Ili+d){b} +- 1
SET b,(Ill+d)
4
23
RES b,s
S{b} ^ 0
RES b,s
Same as for SET
Instruction
JUMP
GROUP
8080
MNEMONIC
OPERATION
MNEMONIC
■ // OF
BYTES
# OF
T STATES
JMP nn
PC -<- nn
JP nn
3
10
JZ nn
If zero, then JMP
JP Z.nn
3
10
else continue
109
JNZ nn
JC nn
JNC nn
JPO nn
JPE nn
JP nn
JM nn
JO nn
JNO nn
JMPR nn
JRZ nn
JRNZ nn
JRC nn
JRNC nn
DJNZ nn
PCHL
PCIX
PCIY
If not zero
If carry
if not carry
if parity odd
if parity even
if sign positive
if sign negative
If overflow
if no overflow
PC PC + e
where e = nn - PC
-126< e< 129
if zero, then JMPR
else continue
if not zero
if carry
If not carry
B ^ B - 1
if B=0 then continue
else JMPR
PC 1- HL
PC ^ IX
PC U
JP NZ,nn
JP C,nn
JP NC,nn
JP PO.nn
JP PE,nn
JP P,nn
JP M,nn
JP PE,nn
JP PO,nn
JR e
JR Z,e
JR NZ,e
JR C,e
JR NC,e
DJNZ e
JP (HL)
JP (IX)
JP (lY)
3
3
3
3
3
3
3
3
3
2
2
2
2
2
1
2
2
10
10
10
10
10
10
10
10
10
12
7/12
7/12
7/12
7/12
8/13
4
8
8
CALL AND RETURN GROUP
8080
MNEMONIC
CALL nn
CZ nn
CNZ nn
CC nn
OPERATION
(SP-1) - PC/H
(SP-2) ^ PC/l
SP SP-2
PC -(- nn
if zero, then CALL
else continue
if not zero
if carry
ZILOG
MNEMONIC
CALL nn
CALL Z,nn
CALL NZ.nn
CALL C,nn
0 OF
BYTES
3
3
// OF
T STATES
17
10/17
10/17
10/17
110
CNC nn
If
not carry
CALL NC.nn
3
10/17
CPO nn
If
parity odd
CALL PO.nn
3
10/17
CPE nn
if
parity even
CALL PE.nn
3
10/17
CP nn
If
sign positive
CALL P,nn
3
10/17
CM nn
if
sign negative
CALL M,nn
3
10/17
CO nn
If
overflow
CALL PE,nn
3
10/17
CNO nn
if
no overflow
CALL PO,nn
3
10/17
RET
PC/H (SP+1)
PC/L ^ (SP)
SP SP+2
RET
10
RZ
if zero, then RET
else continue
RET Z
5/11
RNZ
if
not zero
RET NZ
5/11
RC
if
carry
RET C
5/11
RNC
if
not carry
RET NC
5/11
RPO
if
parity odd
RET PO
5/11
RPE
If
parity even
RET PE
5/11
RP
if
sign positive
RET P
5/11
RM
if
sign negative
RET M
5/11
RO
if
overflow
RET PE
5/11
RNO
if
no overflow
RET PO
5/11
RET I
return from interrupt
RETl
2
14
RETN
return from non-
maskable interrupt
RETN
2
14
RST n
(SP-1) ^ PC/H
RST n
1
11
(SP-2) *■ PC/L
PC 8 * n
where 0£ n< 8
INPUT AND OUTPUT GROUP
8080
MNEMONIC
IN n
INP r
OPERATION
A ^ In
r ^ 1(C)
ZILOG
MNEMONIC
IN A,(n)
IN r,(C)
# OF
BYTES
2
2
if OF
T STATES
11
12
111
INI
INIR
IND
INDR
OUT n
OUTP r
OUTI
OUTIR
OUTD
OUTDR
(HL) ^ 1(C) INI
B ^ B - 1
HL HL + 1
repeat INI until B=0 INIR
(HL) 1(C) IND
B ^ B - 1
HL ^ HL - 1
repeat IND until B=0 INDR
On -<- A OUT (n) ,A
0(C) r OUT (C),r
0(C) *- (HL) OUTI
B ^ B - 1
HL ^ HL + 1
repeat OUTI until B=0 OTIR
0(C) (HL) OUTD
B ^ B - 1
HL HL - 1
2
2
2
2
2
2
2
2
repeat OUTD until B=0
OTDR
16
16/21
16
16/21
11
12
16
16/21
16
16/21
112
APPENDIX B
A ^ r 1 1
<^ P T
00
Ctrl
-@
(NUL)
20
space
@
60
01
Ctrl
-A
(SOH)
2 1
1
k]
A
61
a
02
Ctrl
- B
( STX)
22
1 1
m
B
62
b
03
Ctrl
-c
( ETX)
23
#
^43
C
63
c
0^
Ctrl
- D
(EOT)
2i*
$
D
Sh
d
05
Ctrl
- E
( ENQ)
25
%
E
65
e
06
Ctrl
- F
(AC K)
26
&
i46
F
66
f
07
Ctrl
-G
(BEL)
27
1
47
G
67
g
08
Ctrl
-H
(BS )
28
(
i*8
H
68
h
09
Ctrl
- 1
(HT )
29
)
hS
1
69
i
0A
Ctrl
-J
( LF )
2A
J
6A
j
0B
C t r
- K
( VT )
2B
+
K
6B
k
0C
Ctrl
- L
( FF )
2C
i»C
L
6C
1
0D
Ctrl
-M
(CR )
2D
-
4D
M
6D
m
0E
Ctrl
- N
(SO )
2E
4E
N
6E
n
0F
C t r
- 0
(SI )
2F
/
kF
0
6F
o
10
C t r
- P
(OLE)
30
0
50
P
70
P
1 1
C t r
-Q
(DCl)
31
1
51
Q
7]
q
1 2
Ct r
- R
(DC2)
32
2
52
R
72
r
1 3
C tr
-s
(DC3)
33
3
53
S
73
s
I k
C t r
-T
iock)
3^
5h
T
7k
t
1 5
C t r
-u
( NAK)
35
5
55
U
75
u
1 6
Ct r
-V
( SYN)
36
6
56
V
76
V
1 7
C t r
-w
(ETB)
37
7
57
w
77
w
18
C t r
- X
(CAN)
38
8
58
X
78
X
19
Ctr
- Y
(EM )
39
9
59
Y
79
y
1 A
C tr
-z
(SUB)
3A
5A
Z
7A
z
1 B
C t r
-[
(ESC)
36
t
58
[
7B
{
1 C
C t r
-\
(FS )
3C
<
5C
\
7C
1
1 D
C t r
-]
(GS )
3D
5D
]
7D
}
1 E
C t r
( RS )
3E
>
5E
7E
\,
I F
C t r
(US )
3F
?
5F
7F
DEL
113
HEX
00
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
10
11
12
13
14
15
16
17
18
19
lA
APPENDIX C
8080 Disassembler
(Including Single Byte Z-80 Instructions)
EXTENDED
OP CODE
nn
n
N
-2
e
im
n
-2
MNE^^ONIC
NOP
LXI B,nn
STAX B
INX B
INR B
DCR B
MVI B,n
RLC
EXAF
DAD B
LDAX B
DCX B
INR C
DCR C
MVI C,n
RRC
DJNZ nn
LXI D,nn
STAX D
INX D
INR D
DCR D
MVI D,n
RAL
JMPR nn
DAD D
LDAX D
HEX
IB
IC
ID
IE
IF
20
21
22
23
24
25
26
27
28
29
2A
2B
2C
2D
2E
2F
30
31
32
33
34
35
EXTENDED
OP CODE
N
-2
e
nn
nn
n
-2
nn
n
e ^
nn
nn
MNEMONIC
DCX D
INR E
DCR D
MVI E,n
RAR
JRNZ nn
LXI H,nn
SHLD nn
INX H
INR H
DCR H
MVI H,n
DAA
JRZ nn
DAD H
LHLD nn
DCX H
INR L
DCR L
MVI L,n
CMA
JRNC nn
LXI SP,nn
STA nn
INX SP
INR M
DCR M
114
EXTENDED
HEX OP CODE MNEMONIC
36 n MVI M,n
37 STC
_2
38 e JRC nn
39 DAD SP
3A nn LDA nn
3B DCX SP
3C INR A
3D DCR A
3E n MVI A,n
3F CMC
40 MOV B,B
41 MOV B,C
42 MOV B,D
43 MOV B,E
44 MOV B,H
45 MOV B,L
46 MOV B,M
47 MOV B,A
48 MOV C,B
49 MOV C,C
4A MOV C,D
48 MOV C,E
4C MOV C,H
4D MOV C,L
4E MOV C,M
4F MOV C,A
50 MOV D,B
51 MOV D,C
52 MOV D,D
53 MOV D.E
EXTENDED
HEX OP CODE MNEMONIC
54 MOV D,H
55 MOV D,L
56 MOV D,M
57 MOV D,A
58 MOV E,B
59 MOV E,C
5A MOV E,D
SB MOV E,E
5C MOV E,H
5D MOV E,L
5E MOV E,M
5F MOV E,A
60 MOV H,B
61 MOV H,C
62 MOV H,D
63 MOVH,E
64 MOV H,H
65 MOV H,L
66 MOV H,M
67 MOV H,A
68 MOV L,B
69 MOV L,C
6A MOV L,D
6B MOV L,E
6C MOV L,H
6D MOV L,L
6E MOV L,M
6F MOV L,A
70 MOV M,B
71 MOV M,C
115
EXTENDED
HEX OP CODE MNEMONIC
72 MOV M,D
73 MOV M,E
74 MOV M,H
75 MOV M,L
76 HLT
77 MOV M,A
78 MOV A,B
79 MOV A,C
7A MOV A,D
7B MOV A,E
7C MOV A,H
7D MOV A,L
7E MOV A,M
7F MOV A, A
80 ADD B
81 ADD C
82 ADD D
83 ADD E
84 ADD H
85 ADD L
86 ADD M
87 ADD A
88 ADC B
89 ADC C
8A ADC D
8B ADC E
8C ADC H
8D ADC L
8E ADC M
8F ADC A
EXTENDED
HEX OP CODE MNEMONIC
90 SUB B
91 SUB C
92 SUB D
93 SUB E
94 SUB H
95 SUB L
96 SUB M
97 SUB A
98 SBB B
99 SBB C
9A SBB D
9B SBB E
9C SBB H
9D SBB L
9E SBB M
9F SBB A
A0 ANA B
Al ANA C
A2 ANA D
A3 ANA E
A4 ANA H
A5 ANA L
A6 ANA M
A7 ANA A
A8 XRA B
A9 XRA C
AA XRA D
AB XRA D
AB XRA E
AC XRA H
116
EXTENDED
HEX OP CODE MNEMONIC
AD XRA L
AE XRA M
AF XRA A
B0 ORA B
81 ORA C
B2 ORA D
B3 ORA E
B4 ORA H
B5 ORA L
B6 ORA M
B7 ORA A
B8 CMP B
B9 CMP C
BA CMP D
BB CMP E
BC CMP H
BD CMP L
BE CMP M
BF CMP A
C0 RNZ
CI POP B
C2 nn JNZ NN
C3 im JMP nn
C4 im CNZ nn
C5 PUSH B
C6 n ADI n
C7 RST 0
C8 RZ
C9 RET
CA im JZ nn
EXTENDED
HEX OP CODE MNEMONIC
CC nn CZ nn
CD nn CALL nn
CE n ACI n
CF RST 1
D0 RNC
Dl POP D
D2 nn JNC nn
D3 n OUT n
D4 nn CNC nn
DS PUSH D
D6 n SUI n
D7 RST 2
D8 RC
D9 EXX
DA nn JC nn
DB LDAX B
DC nn CC nn
DE n SBB n
DF RST 3
E0 RPO
El POP H
E2 nn JPO nn
E3 XTHL
E4 nn CPO nn
E5 PUSH H
E6 n ANI n
E7 RST 4
E8 RPE
E9 PCHL
EA nn JPE nn
117
EXTENDED
HEX OP CODE MNEMONIC
EB XCHG
EC nn CPE nn
EE n XRI n
EF RST 5
F0 RP
Fl POP PSW
F2 nn JP nn
F3 DI
F4 nn CP nn
F5 PUSH PSW
EXTENDED
HEX OP CODE MNEMONIC
F6 n ORI n
F7 RST 6
F8 RM
F9 SPHL
FA nn JM nn
FB EI
FC nn CM nn
FE n CPI n
FF RST 7
118
APPENDIX D
Z-80 Extension Disassembler
HEX
EXTENDED
OP CODE
MNEMONIC
HEX
EXTENDED
OP CODE
MNEMONIC
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
00
01
02
03
04
05
06
07
08
09
0A
0B
0C
0D
0E
0F
10
11
12
13
14
15
16
17
18
19
lA
IB
RLC B
RLC C
RLC D
RLC E
RLC H
RLC L
RLC (HL)
RLC A
RRC B
RRC C
RRC D
RRC E
RRC H
RRC L
RRC (HL)
RRC A
RL B
RL C
RL D
RL E
RL H
RL L
RL (HL)
RL A
RR B
RR C
RR D
RR E
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
IC
ID
IE
IF
20
21
22
23
24
25
26
27
28
29
2A
2B
2C
2D
2E
2F
38
39
3A
3B
3C
3D
3E
3F
RR H
RR L
RR (HL)
RR A
SLA B
SLA C
SLA D
SLA E
SLA H
SLA L
SLA (HL)
SLA A
SRA B
SRA C
SRA D
SRA E
SRA H
SRA L
SRA (HL)
SRA A
SRL.B
SRL C
SRL D
SRL E
SRL H
SRL L
SRL (HL)
SRL A
119
HEX
EXTENDED
OP CODE
MNEMONIC
HEX
EXTENDED
OP CODE
MNEMONIC
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
40
41
42
43
44
45
46
47
48
49
4A
4B
4C
4D
4E
4F
50
51
52
53
54
55
56
57
58
59
5A
5B
5C
5D
BIT 0
BIT 0
BIT 0
BIT 0
BIT 0
BIT 0
BIT 0
BIT 0
BIT I
BIT 1
BIT 1
BIT 1
BIT 1
BIT 1
BIT 1
BIT 1
BIT 2
BIT 2
BIT 2
BIT 2
BIT 2
BIT 2
BIT 2
BIT 2
BIT 3
BIT 3
BIT 3
BIT 3
BIT 3»H
BIT 3,L
B
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
5E
5F
60
61
62
63
64
65
66
67
68
69
6A
6B
6C
6D
6E
6F
70
71
72
73
74
75
76
77
78
79
7A
7B
BIT 3
BIT 3
BIT 4
BIT 4
BIT 4
BIT 4
BIT 4
BIT 4
BIT 4
BIT 4
BIT 5
BIT 5
BIT 5
BIT 5
BIT 5
BIT 5
BIT 5
BIT 5
BIT 6
BIT 6
BIT 6
BIT 6
BIT 6
BIT 6
BIT 6
BIT 6
BIT 7
BIT 7
BIT 7
BIT 7
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
120
EXTENDED
HEX OP CODE
MNEMONIC
HEX
EXTENDED
OP CODE
MNEMONIC
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
7C
7D
7E
7F
80
81
82
83
84
85
86
87
88
89
8A
8B
8C
8D
8E
8F
90
91
92
93
94
95
96
97
98
99
BIT 7
BIT 7
BIT 7
BIT 7
RES 0
RES 0
RES 0
RES 0
RES 0
RES 0
RES 0
RES 0
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 1
RES 2
RES 2
RES 2
RES 2
RES 2
RES 2
RES 2
RES 2
RES 3
RES 3
H
L
CHL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
9A
9B
9C
9D
9E
9F
A0
Al
A2
A3
A4
A5
A6
A7
A8
A9
AA
AB
AC
AD
AE
AF
B0
Bl
B2
B3
B4
B5
B6
B7
RES 3
RES 3
RES 3
RES 3
RES 3
RES 3
RES 4
RES 4
RES 4
RES 4
RES 4
RES 4
RES 4
RES 4
RES 5
RES 5
RES 5
RES 5
RES 5
RES 5
RES 5
RES 5
RES 6
RES 6
RES 6
RES 6
RES 6
RES 6
RES 6
RES 6
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
121
HEX
EXTENDED
OP CODE
MNEMONIC
HEX
EXTENDED
OP CODE
MNEMONIC
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
B8
B9
BA
BB
BC
BD
BE
BF
C0
CI
C2
C3
C4
C5
C6
C7
C8
C9
CA
CB
CC
CD
CE
CF
D0
Dl
D2
D3
D4
D5
RES 7
RES 7
RES 7
RES 7
RES 7
RES 7
RES 7
RES 7
SET 0
SET 0
SET 0
SET 0
SET 0
SET 0
SET 0
SET 0
SET 1
SET 1
SET 1
SET 1
SET 1
SET 1
SET 1
SET 1
SET 2
SET 2
SET 2
SET 2
SET 2
SET 2
H
L
(HL)
A
B
C
D
E
H
L
(HL)
A
B
C
D
E
H
L
CHL)
A
B
C
D
E
H
L
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
CB
D6
D7
D8
D9
DA
DB
DC
DD
DE
DF
E0
El
E2
E3
E4
E5
E6
E7
E8
E9
EA
EB
EC
ED
EE
EF
F0
Fl
F2
F3
SET 2,(HL)
SET 2, A
SET 3,B
SET 3,C
SET 3,D
SET 3,E
SET 3,H
SET 3,L
SET 3,(HL)
SET 3, A
SET 4,B
SET 4,C
SET 4,D
SET 4,E
SET 4,H
SET 4,L
SET 4,(HL)
SET 4, A
SET 5,B
SET 5,C
SET 5,D
SET 5,E
SET 5,H
SET 5,L
SET 5,(HL)
SET 5, A
SET 6,B
SET 6,C
SET 6,D
SET 6,E
122
EXTENDED EXTENDED
HEX
OP CODE
MNEMONIC
HEX
OP
CODE
MNEMONIC
CB
F4
SET 6,H
DD
70
d
LD (IX+d) ,B
CB
F5
SET 6,L
UD
71
d
LU (IX+d),C
CB
F6
SET 6,(HL)
DD
72
d
LD (IX+d) ,D
CB
F7
SET 6, A
DD
73
d
LD (IX+d),E
CB
F8
SET 7,B
DD
74
d
LD (IX+d) ,H
CB
F9
SET 7,C
DD
75
d
LD (IX+d),L
CB
FA
SET 7,D
DD
77
d
LD (IX+d), A
CB
FB
SET 7,E
DD
7n
d
LD A.(IX*d)
CB
FC
SET 7,H
DD
36
d
ADD A, (IX+d)
CB
FD
SET 7,L
DD
3E
d
ADC A, (IX+d)
CB
FE
SET 7,(HL)
DD
96
d
SUB (IX+d)
CB
FF
SET 7, A
DD
9E
d
SBC A, (IX+d)
DD
09
DAD IX, BC
DD
A6
d
AND (IX+d)
DD
IQ
DAD IX, DE
DD
AH
d
XOR (IX+d)
DD
21 nn
LD IX, nn
DD
B6
d
OR (IX+d)
DD
22 nn
LD (nn),IX
DD
BH
d
CP (IX+d)
DD
23
INC IX
DD
CB
d 06
RLC (IX+d)
DD
29
DAD IX, IX
DD
CB
d 0E
RRC (IX+d)
DD
2A nn
LD IX, (nn)
DD
CB
d 16
RL (IX+d)
DD
2B
DEC IX
DD
CB
d IP.
RR (IX+d)
DD
34 d
INC (IX+d)
DD
CB
d 26
SLA (IX+.l)
DD
35 d
DEC (IX+d)
DD
CB
d 2r;
SRA (IX+d)
DD
36 d n
LD (IX+d),n
DD
CB
d 3E
SRLR (IX+d)
DD
39
DAD IX, SP
DD
CB
d 46
BIT 0,(IX+d)
DD
46 d
LD B,(IX+d)
DD
CB
d 4E
BIT l,(IX+d)
DD
4E d
LD C,(IX+d)
DD
CB
d 56
BIT 2, (IX+d)
DD
56 d
LD D,(IX+d)
DD
CB
d 5E
BIT 3, (IX+d)
DD
5E d
LD E,(IX+d)
DD
CB
d 66
BIT 4, (IX+d)
DD
66 d
LD M,(IXt-d)
DD
CB
d 6E
BIT 5, (IX+d)
DD
6E d
LD L,(IX+d)
DD
CB
d 76
BIT 6, (IX+d)
123
ntA
EXTENDED
Ur LUUt
MNEMONIC
HFY
riEA
EXTENDED
np mnF
Ur V^UUE
MINeMUN IL.
nn
PR A 7F
RTT
DX 1
Fn
HU
RFTT
tvC i X
nn
uu
PR H SA
DFQ
JO, ^iA+Q }
pn
EU
AT!
I n D A
LiU K, A
nn
uu
PR A SP
RF<?
icno
1 f \ i A^Cl J
pn
EU
QRP nP
ODV^ UE
nn
uu
PR H (if,
UPt;
KED
9 fTY^-A^
i. f ^iA+U )
Fn
OO lUl
I n Tnnl np
LlU ^IIJI ) y UC
nn
uu
PR 1-1 QF
J f \ 1 A^a J
pn
EU
';7
O 1
T n A T
IjU Ay X
nn
uu
PR rl A A
DFQ
H , ^^ 1 A+U )
Fn
cu
A
On.
Anp HI np
nn
uu
PR A AF
RF<;
D P ^ 1 ATQ J
pn
cu
CD nn
Ou lUl
I n np fnn"\
ijU UC , ^iUL )
nn
uu
PR A RA
Li D CI DO
RFQ
O , ^ 1 Atq j
pn
cu
i^F
Or
I n A R
LlU /\, I\
nn
uu
PR A RF
V^D a DC
7 fTX+fil
pn
cu
A?
CRP HI HI
o Dv> nij , nij
nn
uu
PR H Pfi
Fn
67
RRD
nn
uu
PR f1 PF
OC 1
i , ^ 1 A+Q J
ED
6A
ADC HL HL
nn
uu
PR A nA
UD Q UO
CPT
z y ^ 1 A+a J
Fn
6F
RLD
nn
uu
PR <^ nF
OC 1
J f [_1 A+U J
Fn
cu
77
C RP U T CD
nn
uu
PR r1 FA
L>o Q no
QFT
oC 1
t , ^ 1 AtQ j
Fn
7'^ nn
I n Cnn">
LlU ^_nn J , Or
nn
uu
PR A FF
<?FT
OC 1
0,^1 A*C1 J
Fn
cu
7A
Anp HI QP
AULi riLiyOr
nn
PR fl FA
OC 1
O , 1 A*C1 J
Fn
7R
I n Tnn"!
LiLf Or , ^1111 J
nn
uu
PR A FF
LiD CL r c
QFT
OE 1
/ f \^ i A+Q )
pn
cu
A^
I ni
LlUX
nn
uu
PI
El
POP
IX
pn
EU
A1
PPT
L>r X
nn
uu
EJ
EX
(SP),IX
Fn
nu
AS
I nn
LiUU
nn
uu
PUSH IX
pn
cu
AQ
H J
ppn
or U
•
nn
uu
PQ
E7
JP
(IX)
pn
EU
Rd
T nx D
LiUXK
nn
uu
PQ
LD SP,IX
pn
EU
Dl
PDTD
C^r XK
pn
cu
SBC
HL,BC
pn
EU
R8
Do
I nnR
LiUUK
pn
cu
to 1111
LD
(nn) ,BC
pn
cu
RQ
Dy
ppnR
V-ir UK
pn
11
NEC
pn
ID
RETN
cn
ru
See DD instruction.
pn
EU
A7
1 /
LD "
[,A
Substitute
"Y" for every
ED
4A
ADC
HL,BC
"X" - e.g.
ADD IX, IX
ED
4B nn
LD BC,(nn)
becomes ADD IY,IY
124
ANSWERS TO EXERCISES
BITS, BYTES AND BOOLEAN OPERATORS
la) 101
I
+ 0
+ I
X
X
X
2'
2'
= I
0
+ 4
b)
1 101
1
X
2^
= 1
+ 0
X
2'
0
+ 1
X
2^
4
+ 1
X
2^
+ 8
13
f) II00I0I0
0
X
2^
= 0
+
1
X
2'
2
+
0
X
2^
0
+
1
X
2^
8
+
0
X
2^
0
+
0
X
2^
0
+
1
X
2^
64
+
1
X
2^
+ 128
202
c) III0I
d) I0I0II
e) 10000000
1
X
2^ -
1
+
0
X
2'
0
+
1
X
22
4
g)
1 000 1 II 0
=
0
X
2^
+
1
X
2^
8
+
1
X
2'
+
1
X
2^ +
16
+
1
X
29
+
1
X
2^
+
0
X
2^
1
X
2^ =
1
+
0
X
2^
+
1
X
2'
2
+
0
X
2^
+
0
X
2^
0
+
1
X
2^
+
1
X
2^
8
+
0
X
2^
0
+
1
X
2^ +
32
43
0
X 2^
= 0
h)
1 1 1 1 1001
1
X
2«'
+
0
X 2'
0
+
0
X
2'
+
0
2
X 2
0
+
0
X
2^
+
0
X 2^
0
+
X
2^
+
0
4
X 2
0
+
X
2'
+
0
5
X 2^
0
+
X
2^
+
0
X 2^
0
+
X
2^
+
1
X 2^
+ 128
+
X
2^
2
4
8
0
0
0
142
128
= I
0
0
8
16
32
64
+ 128
249
125
) 00010010
j) 01 I 1001 I
: 0
X
= 0
k)
1 1 1000100
=
0
X
2^
= 0
+ 1
X
2'
2
+
0
X
2'
0
+ 0
X
2^
0
+
1
X
2^
4
+ 0
X
2^
0
+
0
X
2^
0
+ 1
X
2^
16
+
0
X
2^
0
+ 0
X
2^
0
+
0
X
2^
0
+ 0
X
2^
0
+
1
X
2^
64
+ 0
X
2^
+ 0
+
1
X
2^
128
1 0
1 0
1
1
Y
A
2^
tZUO
452
1 )
I0I0I0I0I 1
=
1
X
2^
= 1
2^
+
1
X
2'
2
= 1
X
= 1
+
0
X
2^
0
+ 1
X
2'
2
+
1
X
2^
8
+ 0
X
2^
0
+
0
X
2^
0
+ 0
X
2^
0
+
1
X
2^
32
+ 1
X
2^
16
+
0
X
2^
0
+ 1
X
2^
32
+
1
X
2^
128
+ 1
X
2^
64
+
0
X
0
+ 0
X
2"^
+ 0
+
1
X
2'
+512
I 15
683
2a) 6p = 6^ = 0II0B
b) 14^ = = Ill0g
c) 127.
7 r 15 = 7F,, = 01 I I I I I I
16 JJTJ
H
B
d) 280,
256 ^28^
r 24 = I 18^ = 00010001 I000„
n D
e) 542.
256 1342
2 r 30 = 2 IE,, = 00100001 1110
"H
B
I r 14
16 J5^
f) 1077^ = 4 r 53 = 435^ = 0I0000II0I0I
° 256 jrm ^
3 r 5
\6j55
126
g) 4095 = 15 r 255 = FFF^ = llllllllllll
. 256 ^ ^
l_5 r 15
16 y255
h) 8702 = 2 r 510 = 2IFE^
^ 4096 ; 8702 "
I r 254 = 00 1 0000 1 I I I I I I I 0
256 75l¥
l_5 r 14
16 J254
i) 15,430 = 3 r 3142 = 3C46
^ 4096 ) 15430
l_2 r 70 = 001 I I 1000 1 0001 10
256 )3I42
4 r 6
16 J7^
j) 43,751 = l_0 r 2791 = AAE7
° 4096 43751
[0 r 231 = I0I0I0I0I I 1001 I I
256 2791
I4_ r 7
16 231
k) 65,552 = l_ r 16 = 10010
^ 65536 65552
0 r 16 = 00010000000000010000
4096 16
0 r 16
256 16
l_ r 0
16 16
127
I) 70,980 = I r 5444 = 11544
^ 65536 70980
I_rl348 = 000I000I0I0I0I000I00
4096 5444
5 r 68
256 1348
4 r 4
16 68
3a) 000001 11= 7 I I I I 1 000
+ I
I I I I 1001 = -7
b) 00010001 = 17 I I 101 I 10
+ I
I I 101 I I I = -17
c) 000101 I I = 23 I I 101000
+ I
I I 101 001 = -23
d) 001 10000 = 48 I 1001 I I I
+ I
I 1010000 = -48
e) 01 101000 = 104 100101 I I
+ I
1001 1000 = -104
f ) 01 I I I I I I = 127 10000000
+ I
10000001 = -127
4a) 00001001 = 9
128
b) 0001 1001 = 25
c) IIIII0II 00000100
+ I
tmm\t\ = 5, so 1 1 1 1 101 1 = -5
d) 001001 I I = 27^ = 39
n
e) II I 10010 00001 101
+ I
00001 110 = 14, so I I II00I0 = -14
f) II0I0000 00I0IIII
+ I
00110000 = 30^, = 48, so 1101 0000 = -48
5a) 000010! 1=11 No Carry
+ 00001 I I I -t- 15 No Overflow
000 II 0 1 0 26
b) 00010001 = 17 No Carry
-^ I I I0I0I I -K-2I ) No Overflow
I I I I I I 00 -4
c) 00101 I 10
- 00001 100
00 1 000 1 0
46
12
34
No Carry
No Overflow
^ d) 01 101000 ^ 104 No Carry
+ 001 1011 I + 55 Overflow
I00IIIII 159
129
e) 101 1 1 101 - 67
- 01 I0I0I I -107
01 01 0010 -174
No Carry
Overf low
f ) 101 I I 101 - 67 Carry
+ 01 I0I0I I -1-107 No Overflow
I 00101000 40
6a) AND OR XOR
00000000 II0I0I0I II0I0I0I
Carry= 0 C= 0 C= 0
Zero =1 Z= 0 Z= 0
Sign = 0 S= I S= I
Parity=l P= 0 P= 0
b) I0II0I00 llllllll 0I00I0II
C= 0 C= 0 C= 0
Z= 0 Z= 0 Z= 0
S= I S= I S= 0
P= I P= I P= I
C) AND OR XOR
OOOIOIIO llllllll IllOIOOl
C= 0 C= 0 C= 0
Z= 0 Z= 0 Z= 0
S= 0 S= I S= I
P= 0 P= I P= 0
d) I0I000I0 IIII0III 0I0I0I0I
C= 0 C= 0 C= 0
Z= 0 Z= 0 Z= 0
S= I S= I S= 0
P= 0 P= 0 P= I
e) 00010000 1001 1 101 10001 101
C= 0 C= 0 C= 0
Z= 0 Z= 0 Z= 0
S= 0 S= I S= I
P= 0 P= 0 P= 1
130
f ) 00000000 I t I 1 000 1 I 1 1 1 000 1
C= 0 C= 0 C= 0
Z= I Z= 0 Z= 0
S= 0 S= I S= I
P= I P= 0 P= 0
g) 00000000 III Mill llllllll
C= 0 C= 0 C= 0
Z= I Z= 0 Z= 0
S= 0 S= I S= I
P= I P= I P= I
h) II 0011 II II00IIII 00000000
C= 0 C= 0 C= 0
Z= 0 Z= 0 Z= I
S= I S= I S= 0
P= I P= I P= I
WHERE IS MY VARIABLE?
I ) 3080
MOV A,D
MOV D,E
MOV E,A
Z-80
LO A,D
LD D,E
LD E,A
the point is that an
Intermediate storage
area must be use<j
2 ) II I 1 0 1 00
3) After the first instruction HL contains:
2039, so HL now points to a new location.
After the second instruction A contains:
00
4) 3AF334
131
5) Interprets the contents of index register. IX as an address. Takes
that address plus 12 and loads the contents of the byte into
register E.
6) The first loads the value of the two bytes beginning at SPOT into
register pair HL. The second loads the address of SPOT into
register pair HL.
7) AF 4020L,. The registers are swapped.
n
8) No,
9) a) LXI
LO
SP,6F32H (8080)
SP,6F32H (Z-80)
NOTE: Assemblers differ on the form
Hex numbers must be written in. The
assembler will put it in swapped format
within the Instruction.
9) b) BC = 0302
SP = 6F34
10) Here is a blow-by-blow account of the effects:
a) Register A contains the value 3.
b) Memory location 2400 contains the value 3,
c) Index register IX contains, after unswapping, 2403|^,
d ) Reg i ster C conta i ns the va I ue 21.
A METHOD TO OUR LOGIC
I ) 8080
SUB A
ADD M
INX H
ADD M
INX H
ADD M
Z-80
SUB A
ADD A,(HL)
INC HL
ADD A
INC HL
ADD A, (HL)
132
2) MOV A,C
ADD L
MOV L,A
MOV A,B
ADC H
MOV H,A
LF A,C
ADD A,L
LD L,A
LD A,B
ADC A,H
LD H,A
3) Desired bit pattern: I III 1010 = FA|
CPI FAH CP FAH
The zero flag will be set on a match.
4) Signed V XORS = I
Unsigned C = I
5) a) Load into the accumulator the high order byte of RIGA
b) Load into the HL pair the address of the high order byte of BIGB
c) Compare the high order bytes. If they are not equal we are done.
We have our answer in the sign and overflow flags.
d) if the high order bytes were equal, repeat comparison on low order
bytes.
6) To perform HL HL
8080
MOV A,L
SUB C
MOV L,A
MOV A,H
SBB B
MOV H,A
- BC:
Z-80
LD A,L
SUB C
LD L,A
LD A,H
SBC A,B
LD H,A
JUMPS, LOOPS AND MODULAR PROGRAMING
I ) For unsigned numbers
8080 Z-80
a) JC SPOT JP CSPOT
b) JC SPOT JP C,SPOT
JZ SPOT JP Z,SPOT
133
By using these two jumps
one after
the
other.
the = case are
hand 1 ed .
c)
JZ
SPOT
JP
Z,SPOT
d)
JNZ
SPOT
JP
NZ,SPOT
e)
JNC
SPOT
JP
NC,SPOT
f )
JC
SKI P
JR
C,SKIP
JZ
SKIP
JR
Z,SKIP
J MP
SPOT
JP
SPOT
SKIP:
•
•
•
SKIP:
•
•
•
The method used here is to avoid jumping to SPOT if VARA < VARB.
Other techniques are possible as well.
2) For signed numbers. In several instances here, we will want the
the effect of (V XOR S), but there is no single instruction that
will exclusive or flags for us. The following flow chart will
outline the test we must make:
N
/
V XOR S
0
We will use the carry flag to hold the result of (V XOR S).
8080 Z-80
B:
STC
JO
CMC
JP
CMC
NOP
B
(Set the carry)
(Jump if V = 1)
(Now C = V)
(Jump if S = 0)
(Now C = V XOR S)
(Do nothing used so
B can be a label on
an instruction.)
SCF
JP PE,A
CCF
A: JP P,B
CCF
B: NOP
134
At the conclusion of this little sequence of code, the carry flag
can be used just as it was used in unsigned numbers. Let's name
the above sequence VXORS. (If your assembler has macro capability,
look into how you could create a macro named VXORS to perform the
above sequence. )
Now the answer to this exercise can be given. Everywhere VXORS is
used, it means the above five instructions.
8080
Z-80
a)
VXORS
VXORS
JC
SPOT
JP
C,SPOT
b)
VXORS
VXORS
JC
SPOT
JP
C,SPOT
JZ
SPOT
JP
Z,SPOT
c)
JZ
SPOT
JP
Z,SPOT
d)
JNZ
SPOT
JP
NZ,SPOT
e)
VXORS
VXORS
JNC
SPOT
JP
NC,SPOT
f )
VXORS
VXORS
JC
SKIP
JR
C,SKiP
JZ
SKIP
JR
Z,SKIP
J MP
SPOT
JP
SPOT
SKIP: . SKIP:
Except for the addition of VXORS, these are identical to the answers
to exerc i se # I .
3) Inputs: ARYADR - start address of the array
SIZE - number of elements
Outputs: REGISTER A - Sum ( I f no overflow)
OVFLAG - set to a value of 1 if overflow
8080
SUM: PUSH B Save BC register pair
PUSH H Save HL register pair
LHLD ARYADR Fetch start address of the array
135
LOOP:
OK:
DONE:
SUB
STA
LDA
ANA
JZ
MOV
SUB
ADD
J NO
MVI
STA
J MP
I NX
OCR
JNZ
POP
POP
RET
A
OVFLAG
SIZE
A
DONE
B,A
A
M
OK
A, I
OVFLAG
DONE
H
B
LOOP
H
8
Zero the accumulator
Clear overflow flag
Fetch the number of elements
Checks to see If there are zero elements in
the array without changing the value in A
If there are none, we're done. The sum is
correctly reported as zero
Otherwise, move the size to register B
Zero the sum
Add array va I ue
Jump if no overflow occurred
Otherwise A -<- I
Set the overflow flag
Done
Next e I ement
Decrement count
Repeat unt i I done
Restore HL pair
Restore BC pa i r
Z-80
SUM:
LOOP:
OK:
DONE:
PUSH BC
PUSH HL
LD HL, (ARYADR)
SUB A
LD (OVFLAG), A
LD A, (SIZE)
AND A
JR Z,DONE
LD B,A
SUB A
ADD A,(HL)
JP PO,OK
LD A, I
LD (OVFLAG), A
JR DONE
INC HL
DJNZ LOOP
POP HL
POP BC
RET
Save BC register pair
Save HL register pair
Fetch start address of the array
Zero the accumulator
Clear the overflow flag
Fetch the number of elements
Checks to see if there are zero elements in
the array without changing the value in A
If there are none, we're done. The sum is
correctly reported as zero
Otherwise, move the size to register B
Zero the sum
Add array va I ue
Jump If no overflow occurred
Otherwise A ^ I
Set the overflow flag
Done
Next element
Decrement count
Restore HL pa i r
Restore BC pair
136
4) Other methods are possible, but this one first compares high order
bytes, if equal, then low order bytes.
8080
7.
LHLD
BIGB
(Fetch BIGB)
LD
LDA
BIGA+1
(Fetch high order byte of BIGA)
LD
CMP
H
(Compare high order)
CP
JZ
CKLOW
(If equal, check low)
JR
JC
CALB
(A conditional call won't work
JR
J MP
CALA
here. Why?)
JR
CKLOW:
LDA
BIGA
(Fetch low order byte of BIGA)
CKLOW:
LD
CMP
L
(Compare low order)
CP
JNC
CALA
(Jump if BIGA larger)
JR
CALB:
CALL
BBIGR
CALB:
CALL
JMP
DONE
(To avoid calling ABIGR upon
return from BBIGR)
JP
CALA:
CALL
ABIGR
CALA:
CALL
DONE:
DONE:
Z-80
5) Simply insert "VXORS" right after the "Compare High Order."
Why is it not needed after the "Compare Low Order"?
6) Continued on next page.
8080
Z-80
LDA COUNT (Fetch # of clients; this time we
wi I I assume that count ^ 0)
MOV B,A (Save in register B)
LXI H, PEOPLE (Start address of the array)
LXI D,3 (Increment for the address)
MVI A,0FAH (FAl, is the desired descriptor byte)
n
LOOP: CMP M (Compare to person in Array) L(X)P:
JZ MATCH (Jump if match found)
DAD D (Increment to next person)
DCR B (Repeat until Match or Done)
JNZ LOOP
CALL NOSUCH (No match found)
LD A, (COUNT)
LD
LD
LD
LD
CP
JR
ADD
DJNZ
B,A
HL, PEOPLE
DE.3
A,0FAH
(HL)
Z, MATCH
HL,DE
LOOP
CALL NOSUCH
MATCH: I NX
MOV
H
E,M
(To point to jump address)
(Fetch low order byte)
MATCH: INC HL
LD E,,(HL)
137
INX H (To point to high order) INC HL
MOV D,M (Fetch high order byte) LD D,(HL)
XCHG (Jump address in HL) EX DE,HL
PCHL (Jump) JP (HL)
Match could be included inside the loop by changing the jump on zero to
a jump on non-zero and skipping around this piece of code. The only
reason it's not done that way here is to clearly separate the two
prob I ems:
a) looping through PEOPLE looking for a match, and
b) transferring to the jump address, when a match is found,
NOTE: A structure such as PEOPLE which contains jump addresses is often
called a vector table. The jump address itself is usually called
a vector.
BIT FIDDLING AND MESSAGE MAKING
I) Input: MLTPLR two eight bit positive numbers
MLTCND
Output: PRODCT a two byte product of the two inputs
The 8080 version of this subroutine and its Z-80 counterpart will
differ significantly owing to the ability of the Z-80 to rotate
and shift any desired register, The two routines will therefore
be presented separately.
8080
Mu 1 1 i p 1 y
Subrout i ne
PUSH
PSW
SAVE REGISTERS
PUSH
B
PUSH
D
LDA
MLTPLR
Fetch mu 1 1 i p 1 i er
MOV
E,A
Save in low order byte of DE pair
LDA
MLTCND
Fetch multipl icand
MOV
C,A
Save in register C,
MVI
B,8
Load the loop counter in B.
tm
D,0
Zero high order byte of DE pair
138
LOOP: MOV A,E To check bit 0 of the multiplier
RRC Shift bit 0 into carry
JNC NOADD If it is zero, skip the addition
MOV A,D if set, add the multiplicand to the
ADD C order byte
MOV D,A Replace the result
NOADD: MOV A,D The apparent redundancy is due to the case
where the original move to A from D was
ski pped
ANA A Clear carry
RAR Shift high order byte
MOV D,A Replace the result
MOV A,E Fetch low order byte
RAR Shift low order byte bringing in bit 0
of the high order byte
MOV E,A Replace low order byte
DCR B Loop increment
JNZ LOOP Repeat unti I done
XCHG Swap DE and HL
SHLD PRODCT The result was in the DE pair
XCHG Swap back
POP D
POP B
POP PSW
RET Done
Z-80 Multiply Subrout i ne
MLTPLY: PUSH AF Save registers
PUSH BC
PUSH DE
ID A,(MLTPLR) Fetch mu I t i p I ier
LD E,A Save in low order byte of DE pair
LD A,(MLTCND) Fetch mu It ip I icand
LD C,A Save in register C
LD B, 8 Load the loop counter in B
SUB A Clear the A register. Registers A and E
will be used as a pair during formation
of the product
LOOP: BIT 0,E Check bit 0 of the multiplier
JR Z, NOADD If it is zero, skip the addition
139
NOADD :
ADD
SRL
RR
DJNZ
LD
LD
A,C
A
E
LOOP
D,A
If set, add the multiplicand to the high
order byte
Shift the high order byte right
Shift the low order byte bringing in bit
0 of the high order byte
Repeat unt i I done
Place high order byte of product into high
order byte of DE pair
(PRODCT),DE Store result
POP
POP
POP
RET
DE
BC
AF
Restore registers
Done
2) Inputs: MLTPLR Two eight bit numbers not necessarily positive
MLTCND
PRODCT A two byte product of the two inputs
808IZ)
Comments
Z-80
MULT2: PUSH
PUSH
PUSH
MVI
LDA
MOV
ANA
JP
CMA
INR
INR
POS 1: STA
LDA
MOV
ANA
JP
CMA
INR
PSW
H
D
H,0
MLTPLR
E,A
A
POS 1
A
H
MLTPLR
MLTCND
D,A
A
POS 2
Save registers MULT2:
PUSH AF
PUSH BC
PUSH DE
Clear sign of LD B,0
result flag
Fetch first operand LD A, (MLTPLR)
Save in E LD E,A
Test sign of number AND A
Skip complement if JP P,POS 1
positive
Form 2's complement if NEG
negative
Increment sign of result INC B
flag
Replace positive POS 1: LD (MLTPLR), A
mu 1 1 i p I i er
Fetch second operand LD A, (MLTCND)
Save in D LD D,A
Test sign of number AND A
Skip complement if JP P,POS 2
positive
Form 2 ' s comp 1 ement i f NEG
negative
140
INR
POS 2: STA
CALL
MOV
RAR
JNC
LHLD
MOV
CMA
MOV
MOV
CMA
MOV
INX
SHLD
RESPOS: MOV
STA
MOV
STA
POP
POP
POP
RET
H
MLTCND
MLTPLY
A,H
RESPOS
PRODCT
A,H
H,A
A,L
L,A
H
PRODCT
A,E
MLTPLR
A,D
MLTCND
D
H
PSW
Increment sign of result
flag
Replace positive POS 2;
multipl icand
Get positive result in
product
Test bit 0 of sign of
result flag
If the bit is 0 the result
is positive. Otherwise
complement the result
Fetch the result
Form 1 ' s comp I ement
of each byte
INC
LD
CALL
BIT
Increment register pair
for 2's complement
Store the properly signed
result
LD
LD
CPL
LD
LD
CPL
LD
INC
LD
Restore initial
signed inputs in
MLTPLR and MLTCND
Restore registers
Done
RESPOS: LD
LD
LD
LD
POP
POP
POP
RET
(MLTCND), A
MLTPLY
0,B
JR Z, RESPOS
BC, (PRODCT)
A,B
8, A
A,C
C,A
BC
( PRODCT ),BC
A.E
(MLTPLR), A
A,D
(MLTCND), A
DE
BC
AF
- A two byte positive number
- A one byte positive number
- A one byte positive quotient
- A one byte positive remainder or a flag
value of -I on overflow
Again, separate 8080 and Z-80 versions will be given.
8080 Division Subroutine
DIVIDE: PUSH PSW Save registers
PUSH B
PUSH D
3) Inputs: DIVDND
DIVSOR
Outputs: (?OTENT
RMANDR
141
LDED DIVDND Fetch dividend into the DE register pair
LDA DIVSOR Fetch divisor
MOV C,A Save in register C
MVI B,8 Loop counter in register B
LOOP: MOV A,E Shift low order byte to the left
ANA A Clear carry
RAL Shift
MOV E,A Replace value
MOV A,D Fetch high order byte
RAL Rotate bringing in high order bit
SUB C Subtract divisor
JP SETBIT If result was positive, jjmp
ADD C Otherwise add back divisor
MOV D,A Replace high order byte
JMP NEXT Go to increment phase
SETBIT: MOV D,A Replace high order byte
MOV A,E Fetch low order byte
ORI 1 Set low order bit
MOV E,A Replace low order byte
NEXT: OCR B Decrement loop counter
JNZ LOOP Repeat until done
MOV A,E Quotient
ANA A Test sign of result
JP OK If positive, the result is accurate
MVI A,-l Set overflow value
STA RMANDR
JMP DONE Jump
OK: STA QOTENT Save quotient
MOV A,D Remainder
STA RMANDR Save remainder
DONE: POP D Restore Registers
POP B
POP PSW
RET
Z-80 Division Subroutine
DIVIDE: PUSH AF Save registers
PUSH BC
PUSH DE
142
1 n
LU
r»r f n i \/nMn ^
Ut, \u 1 yUviU)
Fetch dividend into the DE register pair
LU
n , V U 1 V oUK ^
Fetch divisor
LD
C,A
Save in register C
LD
B.8
Loop counter in register B
LD
A,D
Will use registers A and E as a pair
uuring TormaTion ot ine quoTienT
LUUr :
C 1 A
t
Shift low order byte
KLA
Rotate high order byte bringing in carry
OUU 1 idC 1 0 t V 1 bor
JP
P SETBIT
If "i"hp rp<^iili' Wr^c: noc:ii"i\/p iiimn
ADD
A C
Jr
NLXI
Go to increment phase
bb 1 B 1 T :
C CT
bt\
Set low order bit
NtX 1 :
r\ 1 M"7
UJ NZ
LUUr
Repeat unti 1 done
□ 1 f
-J r—
Test sign of result
JR
If positive, the result is accurate
1 n
LU
A,-l
Set overflow flag
LD
(KMANUK; , A
ID
JK
UUNt
J ump
uin:
LU
Save rema i nder
LD
A C
A,E
Quot i ent
LD
(vol EN 1 ; ,A
Save quotient
LXJNL :
DAD
rUr
UE
Restore registers
FOP
BC
POP
AF
RET
Done
4) The purpose of this exercise is to illustrate coding of a routine where
three pointers must be maintained. Two pointers can be handled easily
using the DE and HL pairs, but where can a third pointer be stored
conveniently? The answer is to use the top of the stack. Load the
first pointer into HL and push it on the stack. Load the second and
third pointers into the DE and HL register pairs. Now whenever the
first pointer is needed execute an:
XTHL (8080)
EX (SP),HL (Z-80)
With the above hint, the routine should be within the grasp of the
reader.
143
5) Input: WHERE - the address of an array of character
DIGITS - the number of characters in the array
Output: RESULT - a two byte binary number equal to the value input
in the character string
e.g.
WHERE
31 30 30 31
ASCII
RESULT = 0000 0000 0000 1001
Separate 8080 and Z-80 versions will be given. Both will call a
hypothetical routine named WOOPS if:
a) the number of characters as recorded in DIGITS
exceeds 16
b) any character appears in the array that is neither
a 31 ^ or a 30|_|
8080
Convert
Binary Input
CBININ:
PUSH
PSW
Save registers
PUSH
B
PUSH
D
PUSH
H
LDA
DIGITS
Fetch number of characters
CPI
17
Test for too many
CNC
WOOPS
If a carry (borrow) does not occur, call
t WOOPS
MOV
B,A
Save DIGITS as a counter
1 HI n
nncir\u#
OCT poinier to cnaraCTer array
LXI
D,0
Clear DE register to use in forming the
resu 1 t
LOOP:
MOV
A,M
Fetch character
CPI
30H
Is it a "0"?
JZ
OK
Yes, jump
CPI
31H
Is it a "1"?
CNZ
WOOPS
If not, cal 1 WOOPS
OK:
RAR
Shift the 0 or 1 into the carry
MOV
A,E
Fetch low order byte of result
RAL
Rotate digit into result
MOV
E,A
Replace low order byte
MOV
A,D
Fetch high order byte
RAL
Rotate digit into result
MOV
D,A
Replace high order byte
INX
H
Next character
DCR
B
Decrement count
JNZ
LOOP
Repeat unti i done
XCHG
Swap DE and HL
144
SHLD
RESULT
S+orG final result
XCHG
Swap back
POP
H
Restore registers
POP
D
POP
B
POP
PSW
RET
Done
Z-80
Convert
Binary Input
CBININ:
PUSH
AF
Save registers
PUSH
BC
PUSH
DE
PUSH
HL
LD
A, (DIGITS)
Fetch number of characters
CP
17
Test for too many
CALL
NC,WOOPS
If a carry (borrow) does not occur.
LD
B,A
Save DIGITS as a center
LD
HL, (WHERE)
Set pointer to character array
LD
DE,0
Clear DE register to use in forming
LOOP:
LD
A, (HL)
Fetch character
CP
30H
Is it a "0"?
JR
Z,OK
Yes, jump
CP
31H
Is is a "1"?
CALL
NZ,WOOPS
If not, cal 1 WOOPS
OK:
RRA
Shift the 0 or 1 into the carry
RL
E
Rotate digit into low order byte
RL
D
Rotate high order byte
INC
HL
Next character
DJNZ
LOOP
Repeat unt i 1 done
LD
(RESULT), DE
Store final result
POP
HL
Restore registers
POP
DE
POP
BC
POP
AF
RET
Done
6) a) When each character input is a hexadecimal digit, you will want
want to verify that each character in the buffer lies in the range
a) 50^ < Char < 39^ (0-9)
n — — n
b) 41^ < Char < 46^ (A-F)
H ~ — n
c) 61,, < Char < 66,, (a-f)
145
In range a, you will naturally subtract 30^.
hi
In range b, a subtraction of 37|^ will produce the appropriate
hex digit.
In range c, the number to subtract is 57 .
H
After the digit has been isolated, it will occupy the order four
bits of the accumulator. Shifting those bits into the result
should pose no problem.
b) Input: WHERE - the address of the character array
DIGITS - the number of characters in the array
Output: RESULT - a two byte value of the number
During the course of the subroutine, it will be necessary to
multiply a two byte value by 10. The method to be used will
be to multiply the high and low order bytes separately. The
two could then be added as:
high order product
low order product
three byte result |
In fact, however, if the high order byte of the high order
product is non-zero, it will be time to call WOOPS. The sum
would overflow the size of the result.
8080
Decimal to Binary Input Subroutine
DECBIN: PUSH
PUSH
PUSH
PUSH
LDA
CP I
CNC
MOV
LHLD
LXI
PSW
B
D
H
DIGITS
6
WOOPS
B,A
WHERE
D,0
Save registers
Fetch number of digits
The largest signed number that will fit is
32,767
Call if more than five digits (this still
won't guarantee no overflow)
Save count
Load address of character array
Clear DE register for the result
146
LOOP:
MOV
CPI
cc
SUI
MOV
A,M
30H
WOOPS
30H
C,A
Fetch character
Is it under 30H?
Yes, ca I I WOOPS
The digit must be OK, subtract
To get its binary value, save in C. We
now need to multiply the result already
forming by 10. This will be done in two
separate operations.
Mnu
a F
M,t
rsTc^n low ur uci uy i g
o 1 n
Ml TPMD
mil I"f"Ir\ 1 i/^^nH
O 1 Ui c iMU II 1 p 1 1 CaflU
MM 1
nv 1
n, 1 10
o 1 n
Ml TPI D
ML 1 r LK
\ (n rrtiil"^ir>l i£ir"
oTOi 6 1 %J Ob iTiu 1 r 1 p 1 I er
OnLL
Ml TDI V
HL 1 rLT
rnuiTipiy Tne. two
A n
rciv-ii niyii oiutJi uyio
OWap ut anu riL
LHLD
PRODCT
Re+ch result
XCHG
Swap back
STA
MLTCND
Store high order as multiplicand
CALL
MLTPLY
Multiply by same multiplier
LDA
PRODCT+ 1
High order byte
ANA
A
Test for zero
CNZ
WOOPS
If it isn't, cal 1 WOOPS
LDA
PRODCT
Low order byte
ADD
D
Add to- high order of previous product
CO
WOOPS
1 f overf low, ca 1 1 WOOPS
MUV
n A
U, A
Place result in low order
MOV
A,C
Fetch new digit
ADD
E
Add to low order
MUV
C A
t,A
Replace low order
MM T
Clear A without destroying flags
u
nOQ in any carry irom low oraer
IT overriow, ca i i nvurj
MOV
D,A
Replace high order
I NX
H
To point to next digit
DCR
B
Decrement count
JNZ
LOOP
Repeat unt i 1 done
XCHG
Swap OE and HL
SHLD
RESULT
Store result
POP
H
Restore registers
POP
D
POP
B
POP
PSW
RET
Done
147
LOOP:
"7 Qfft
Dec i ma 1 +o
Binary Input Subroutine
A C
Ar
Save registers
Dl 1 C U
rUbn
DP
PI IQU
ut
Dl ICU
ML
LD
A, (DIGITS)
Fetch number of digits
CP
6
The largest signed number that will fit is 32,
CALL
NC,WOOPS
Call if more than five digits (this still won'
yuaranxee no overiiow.^
1 n
R A
oave couni
LU
111 f U/UCTDC ^
HL, IWntKt;
Load address of character array
1 n
LU
Ut, iO
Clear DE register for the result
1 n
LU
A f MM
n, ^ riL 1
reicn cnaracTer
PD
IS IT unoer jioni
1 1
P WPPD c
0, WUUro
Yes, ca 1 1 wuurb
PD
Or
AU
IS IT over jyn I
CALL
NC,WOOPS
Yes, cal 1 WOOPS
SUB
30H
The digit must be OK, subtract
LO
C,A
to get its binary value, save in C, We now
need to multiply the result already forming by
10, This wi 1 1 be done in two separate operatii
1 n
LU
A,t
Fetch low order byte
LU
/ kxi Tr'Mn \ A
KrAL 1 LNU J ,A
Store as multiplicand
1 n
LU
A 1 01
A, 1 10
1 n
LU
1 Ml TPI D ^ A
\ ML 1 r LK J , A
oTore 110 as muiTipi ler
P A 1 1
OnLL
Ml TPI V
riL 1 r L I
Multiply the two
1 n
LU
A n
n, U
rexcn nign oraer oyxe
LU
UC f \ rvtoUL 1 }
reicn resu i t
1 n
LU
(MLTCND),A
Store high order as multiplicand
PA 1 1
MLTPLY
Multiply by same multiplier
1 n
LU
A, (RESULT+DHIgh order byte
AMD
A
Test for zero
PA 1 1
NZ,WOOPS
If it isn't, cal 1 WOOPS
1 n
LU
A, (RESULT)
Low order byte
Ann
nUU
A,D
Add to high order of previous product
PA 1 1
PE,WOOPS
If overflow, cal 1 WOOPS
LU
D,A
Place result in low order
1 n
LU
C
Fetch new digit
Ann
nuu
A,E
Add to low order
LD
E,A
Replace low order
LD
A,0
Clear A without destroying flags
ADC
A,D
Add in any carry from low order
148
CALL PE,WOOPS If overflow, call WOOPS
LD D,A Replace high order
INC HL To point to next digit
DJNZ LOOP Decrement Count
Repeat unt i I done
LD (RESULT), DE Store result
POP HL Restore registers
POP DE
POP BC
POP AF
RET Done
7) Translating back from binary to character should pose no problems in
the case of binary and hexadecimal values. The algorithm for converting
back from binary into decimal is a little trickier. The trick is to
divide the two byte value by 10 and use the remainder as the lowest
order digit. Then divide what's left of the result by 10 again and
so on, so that the character value is created from right to left.
The only problem is that you are very likely to get an overflow on the
first division. How can you break the division into two pieces to
get around this problem?
A CASUAL INTRODUCTION TO DATA STRUCTURES
I) Due to the machine dependent aspects of I/O, it is not possible to
present a routine that is guaranteed to work on your system. The
routine called KYBDIN that accepts a single character from the
keyboard and leaves its value in the accumulator. Echoing is
accomplished by calling a hypothetical routine called VIDOUT which
accepts a single character in the accumulator and displays it on
the screen. It is assumed that this routine does not destroy the
contents of the accumulator.
8080
Str i ng
1 nput
Routi ne
BUFFER:
.BLKB
30
Reserve 30 bytes of storage
STRGIN:
PUSH
PSW
Save registers
PUSH
B
PUSH
H
LXI
H, BUFFER
Set HL to point to the buffer
MVI
A,20H
ASCII for a space
MVI
B,30
Number of characters in buffer
CLRLOP:
MOV
M,A
Clear buffer location
INX
H
Next buffer location
149
DCR B Decrement count
JNZ CLRLOP Repeat until entire buffer cleared
LXI H, BUFFER Reset pointer to start of buffer
MVI B,30 Overflow counter
INLOOP: CALL KYBDIN Get character
CALL VIDOUT Echo
CPI 0DH Carriage return?
JZ DONE Yes, jump out of loop
MOV M,A Else, store in buffer
INX H Next buffer location
DCR B Overflow counter
JNZ INLOOP Repeat if not full
DONE: POP H Restore registers
POP B
POP PSW
RET Done
Z-80 String Input Rout i ne
BUFFER: .BLKB 30 Reserve 30 bytes of storage
STRGIN: PUSH AF Save registers
PUSH BC
PUSH DE
PUSH HL
LD A,20H ASCII for a space
LD (BUFFER), A Clear first character
LD HL, BUFFER Pointer to first character
LD DE,BUFFER+1 Pointer to second character
LD BC,29 Number of characters to be cleared
LDIR Clear buffer
LD B,30 Overflow counter
INLOOP: CALL KYBDIN Get character
CALL VIDOUT Echo
CO 0DH Carriage return?
JR Z,DONE Yes, jump out of loop
LD (HL),A Otherwise, store character
INC HL Next buffer location
DJNZ INLOOP Repeat until full or carriage return
DONE: POP HL Restore registers
POP DE
POP BC
POP AF
RET Done
150
2) See note to exercise #1. The subroutine below uses VIDOUT.
INPUT: WHERE - start address of the buffer
COUNT - number of characters
8080 String Output Routine
STROUT: PUSH PSW Save registers
PUSH B
PUSH H
LHLD WHERE Fetch start address
LDA COUNT Fetch number of characters
MOV B,A Save count
OUTLOP: MOV A,M Fetch character
CALL VIDOUT Output to screen
INX H Next character
OCR B Decrement count
JNZ OUTLOP Repeat until done
POP H Restore registers
POP B
POP PSW
RET Done
Z-80 String Output Routine
STROUT: PUSH AF Save registers
PUSH BC
PUSH HL
LD HL, (WHERE) Fetch start address
LD A, (COUNT) Fetch number of characters
LD B,A Save count
OUTLOP: LD A,(HL) Fetch character
CALL VIDOUT Output to screen
INC HL Next character
DJNZ OUTLOP Decrement count, repeat unti I done
POP HL Restore registers
POP BC
POP AF
RET Done
3) The driver will be a simple matter of moving data and calling STROUT
and STRGIN if the data is structured carefully. When you know in
151
advance the exact message you want output, define it in ASCII in
your data area. Count up the length and store it as a constant as
well. The driver routine will be trivial if the data is defined as
follows (use the keywords your assembler wants to see):
Mbbi :
A COT T
Name:
Mbbz :
A COT T
Address :
MSG3:
.ASCII
"Phone number?"
LENl
.BYTE
5
LEN2:
.BYTE
8
LEN3:
.BYTE
13
NAME:
.BLKB
20
ADDRSS:
.BLKB
30
PHONE:
.BLKB
8 (the extra character
4) The storage area can be reserved using:
. LOC 2000 (or some page boundry address)
POOL: .BLKB 400H
a ) 8080 Link-up Subroutine
LINKUP: PUSH PSW
PUSH B Save registers
PUSH D
PUSH H
LXI H,POOL Start address of space
SHLD AVAIL Avail will point to first node
LXI D,P00L+64 DE will point to next node
LXI B,127 BC=(node size*2) -1 (the reason should become clear late
MVI A, 15 The number of nodes that will fit minus 1.
SETLOP: MOV M,E Low order byte of link
INX H Point to next byte
MOV M,D High order byte of link
DAD B To point to the node after next
XCHG Now HL points to the next node
DCR A Decrement loop counter
JNZ SETLOP Repeat until all nodes have link fields set but the last
MOV M,A Set final I i nk va I ue of a I I 0' s
INX H
MOV M,A
POP H Retore registers
POP D
152
POP B
POP PSW
RET Done
Z-80 Link-up Subroutine
LINKUP: PUSH AF
PUSH BC Save registers
PUSH DE
PUSH HL
LD HL,POOL Start address of space
LD (AVAIL),HL Avail will point to first node
LD DE,P00L+64 DE will point to next node
LD BC,127 BC=(node size*2) -1 (the reason should become clear later)
LD A, 15 The number of nodes that will fit minus 1
SETLOP: LD (HL),E Low order byte of link
INC HL Point to next byte
LD (HL),D High order byte of link
ADD HL,BC To point to the node after next
EX DE,HL Now HL points to the next node
DEC A Decrement loop counter
JR NZ, SETLOP Repeat until all nodes have link fields set but the last
LD (HL),A Set final link value of all 0's
INC HL
LD (HL),A
POP HL Restore registers
POP DE
POP BC
POP AF
RET Done
b) 8080 Get-node Subroutine
GETNOO: PUSH PSW Save registers
PUSH D
LHLD AVAIL Fetch pointer to next available node
MOV A,L Test for all zeroes which would indicate no more
ORA H nodes available
CZ OVFLOW Call hypothetical overflow routine if no nodes are left
MOV E,M Otherwise fetch link field from this node
INX H
MOV D,M
XCHG Swap DE + HL
SHLD AVAIL Set new pointer in avail
153
XCHG Swap back so HL points to new node
POP D Restore registers
POP PSW
RET Done
Z-80 Get-node Subroutine
GETNOD: PUSH AF Save registers
PUSH DE
LD HL, (AVAIL) Fetch pointer to next available node
LD A,L Test for all 0's which would indicate no more nodes
OR H available
CALL Z,OVFLOW Call hypothetical overflow routine if no nodes are
LD E,(HL) Otherwise fetch link field from this node
INC HL
LD D, (HL)
LD (AVAIL),DE Set new pointer in avail
POP DE Restore registers
POP AF
RET Done
c) Since there are no overflow worries, this routine should pose no
problems. A basic attack might involve:
1) fetch value of avail (pointer to next node on avail list)
2) store that pointer in link field of node to be returned
3) store pointer to returned node in avail
BINARY CODED DECIMAL ARITHMETIC
I) The method to be used involves two separate subroutines. The first
subroutine will accept a pointer to a buffer which contains only
digits in character form and will translate from left to right into
BCD. The second subroutine will analyze the original raw input
extracting punctuation and stray characters. It will then call the
first and pass it the byte count and address in register B and the
DE register pair respectively. The final BCD number will be placed
in an array called NUMBER, The first three bytes of NUMBER will be
its descriptor block.
8080 Digit to BCD Subroutine
DGTBCD: PUSH PSW Save registers
PUSH B
PUSH D
154
PUSH
H
LXI
H NUMBER+3
F i r^^i" dp«;1' i i on c;ln+ for RPH
LDAX
FpiT" h rl i n i +
I ^ 1 1 1 VJ 1 ^ 1 1
SUI
30H
nplpfa ASriT rndp
RAL
Ro't'3't'P f ril 1 r + i npc; +o + hta 1 o "f +
PAI
RAL
PAL
MOV
r A
JO VC
I NX
n
L/
Po i n+ +0 npv+ H ? o i +
LDAX
D
Fp+p h npyi" ri i n i +
1 ^IV^II IIC^) Ul^l 1
SUI
30H
np 1 P+p A*^PTT roHp
ADD
c
Tn form RPD n?^ i r nf Hini+c
MOV
M,A
Savp i n niimhpr*
INX
0
Npyf" H i n i +
INX
H
Nlpyi" hv+p in niimhpr
1 1 L/ y 1 w 1 II 1 1 U 1 1 1 L/ w 1
DCR
B
Dpprpmpn't' hv+p ("niiiTt"
L^^VaV 1 S>^l 1 III Lf Y 1 C NirV/U III
JNZ
LOOP
Rpnpa+ unl" i 1 donp
POP
H
Restore rea i s+ers
POP
D
POP
B
POP
PSW
RET
Done
Z-80 Digit to BCD Subroutine
Unlike the 8080 version. This subroutine affects the contents
of the buffer location passed to it.
Save registers
LOOP:
PUSH
AF
PUSH
BC
PUSH
DE
PUSH
HL
LD
HL, NUMBER+3
SUB
A
EX
DE,HL
RRD
LD
(DE),A
INC
HL
RRD
EX
DE,HL
RLD
INC
HL
Pointer to output area
Clear accumulator
Swap pointers so HL points to input buffer
Bring in binary form of first digit
Store i n number
Next character
Bring in binary fomi
Swap pointers to HL points to number
Rotate second digit into number
Next byte
155
INC DE Next digit
DJNZ LOOP Repeat until done
POP HL Restore registers
POP DE
POP BC
POP AF
RET Done
The second subroutine deals with data areas defined as on page 143.
The sizes of BUFFER and NUMBER can be assumed to have been defined
to be large enough to accomodate any number the routine will have
to deal with. That is, the routine needn't do any overflow error
checking. We will also assume that the entire data area for NUMBER
was previously cleared.
8080 Characters to Digits Subroutine
CARTDG: PUSH
PUSH
PUSH
PUSH
SUB
STA
LXI
LXI
PRESIG: LDAX
CPI
JZ
CPI
JZ
CPI
JZ
CPI
JNZ
MVI
STA
J MP
NOMNUS: CPI
JNZ
I NX
J MP
PSW
B
D
H
A
SPRFLG
H, BUFFER
D, BUFFER
D
20H
I NCR
24H
I NCR
2BH
INCR
2DH
NOMNUS
A, -I
NUMBER+2
INCR
2EH
NOPERD
D
POSTDC
Clear accumulator
Clear spare flag
Pointer to Buffer + 0
Same
Fetch character
Is it a space?
Yes , j ump
Is it a "$"?
Yes, jump
Is it a "+"?
Yes, jump
Is it a "-"?
No, jump
Set negative indicator
Place in sign byte
J ump
Is it a "."?
No, jump
Next character
Jump
156
CP I
30H
Is it less than a digit?
JC
TERMSG
Yes, jump
CPI
3AH
Is it greater than a digit?
JNC
TERMSG
Yes. iumo
MOV
M,A
store character
INX
D
Increment buffer pointers
I NX
H
INX
B
Increment digit count
J MP
POSTSG
1 1 imn
INX
D
Next character
J MP
PRESIG
Repeat
etc.
So the whole routine is .just a straightforward coding of the algorithm on
pages 143-146. NOTE: Do not call D6TBCD when the number is zero bytes long.
Z-80 Characters to Digits Subroutine
CARTDG: PUSH AF
PUSH BC
PUSH
DE
PUSH
HL
SUB
A
Clear accumulator
LD
{SPRFLG),A
Clear spare flag
LD
HL, BUFFER
Pointer to Buffer + 0
LD
DE, BUFFER
Same
PRESIG: LD
A,(DE)
Fetch character
CP
20H
Is it a space?
JR
Z,INCR
Yes, jump
CP
24H
Is is a "$"?
JR
Z,INCR
Yes, jump
CP
2BH
Is it a "+"?
JR
Z,INCR
Yes, jump
CP
2DH
Is it a "-"?
JR
NZ, NOMNUS
No, jump
LD
A,-l
Set negative indicator
LD
(NUMBER+2),A
Place in sign byte
JR
I NCR
J ump
NOMNUS: CP
2EH
Is it a "."?
JR
NZ,NOPERD
No, jump
INX
D
Next character
JP
POSTDC
Jump
157
INWr tKU :
_>)0n
Is it less than a digit?
i P
Yes, jump
Is it greater than a digit?
IP
Or
TeS| jump
LU
f HI ^ A
Store character
UC
1 ncremenT DUTrer poinTers
INC
HI
INP
R
1 Mvi dnc?M 1 u 1 y 1 1 v^L'uii 1
JP
POSTSG
Jump
INCR:
INC
DE
Next character
JR
PRESIG
Repeat
etc.
So the whole routine is just a straightforward coding of the algorithm on
pages 143-146. NOTE: Do not call DGTBCD when the number is zero bytes long
2) Fixed point addition;
INPUT: VARA
VARB
SZMAX
OUTPUT: SUM
- are two BCD numbers
number of bytes of storage reserved for each
number input
data area where result will be stored or flag
result of negative zero on overflow
8080
Fixed Point Addition
SUM: .BLKB
ENDSUM: .BLKB
BLXKA: .BLKB
BLOCKB: .BLKB
FXPTAD: PUSH
PUSH
PUSH
PUSH
LXI
LXI
MVI
FXPT05: MOV
STAX
I NX
I NX
H,VARA
B,3
A,M
D
H
D
(for max of 256 byte number and 3 byte descript
(storage area for descriptor blocks of input)
Save registers
258
1
3
3
PSW
B
D
H
D,BLCX2KA Pointer to block save area
Pointer to descriptive block
Number of bytes in block
Transfer block to block save area
158
DCR B
JNZ FXPT05
MVI B,3 Bytes in second block
LXI H,VARB Pointer to second descriptive block (DE already points
to second save area)
FXPT10: MOV A,M Transfer second block to save area
STAX D
I NX H
I NX D
DCR B
JNZ FXPT10
LDA SZMAX Fetch maximum size
MOV C,A Save
(ALIGN DECIMAL POINT)
LDA VARB+1 Number of decimal places in VARB
MOV B,A Save
LDA VARA+1 Number of decimal places in VARA
SUB B Find the difference
MOV D,A Save
JZ FXPT30 Jump if same number of places
JNC FXPT25 Jump if A has more
LXI H,VARA Pointer to size of VARA
FXPT15: ADD M Get new size
CMP C Compare to maximum size
JZ FXPT20 If same, we're OK
CNC OVFLOW If over max, call overflow
FXPT20: MOV M,A Store new size
MOV A,D Restore difference
INX H Pointer to decimal places in variable
ADD M New decimal places
MOV M,A Store new decimal places
STA SUM+1 Store decimal places in sum
JMP FXPT30 Jump
FXPT25: LXI H,VARB Pointer to size of VARB
JMP FXPT15 Get new size
(CHECK SIGN OF NUMBERS)
FXPT30: LDA VARB+2 Sign of VARB
MOV B,A Save
LDA VARA+2 Sign of VARA
CMP B Do signs match?
JNZ FXPT35 No, jump
STA SUMf2 Give their common sign to the result
159
LXI
H,VARA
Pass the parameters to BCD ADD
SHLD
ADDl
LXI
H,VARB
SHLD
ADD2
LXI
H,SUM
SHLD
RESULT
CALL
BCDADD
Add the two numbers
J MP
FXPT55
FXPT35:
LDA
VARB
Size of VARB
MOV
B,A
Save
LDA
VARA
Size of VARA
CMP
B
Are numbers the same size?
JNZ
FXPT45
No , j ump
LX 1
D, VARA+j
First byte of number of VARA
LX 1
H, vAKd+^
r 1 rsT DyTe ot numoer ot vnKd
r XPT40 :
LDAX
D
Fetch byte of VARA
CMP
M
Compare to VARB, same?
JNZ
FXPT45
No, jump
INX
D
Yes, then check next byte
1 NX
H
DCR
B
JNZ
FXPT40
Repeat while bytes remain
SUB
A
The two numbers are equal, so move ;
zero to sum
STA
SUM
STA
SUM+1
STA
SUM+2
J MP
\t I'll
FXPT55
FXPT45:
JC
FXPT50
Jump if VARB is larger
LDA
VARA+2
STA
SUM+2
LXI
H,VARA
Prepare parameters to subtract
VARB
from VARA
SHLD
NMUEND
LXI
H,VARB
SHLD
SBTRHD
LXI
H, SUM
SHLD
DFFRNC
CALL
BCDSUB
Subtract
J MP
J I'll
FXPT55
1 /\l 1 -/
FXPT50:
LDA
VARBT2
STA
SUM+2
LXI
H,VARB
Prepare parameters to subtract
VARA
from VARB
SHLD
MNUEND
LXI
H, VARA
SHLD
SBTRHD
LXI
H,SUM
SHLD
DFFRNC
160
CALL BCDSUB
FXPT55: . The routine is essentially complete, Just
rnove the descriptive blocks back from the save
area, pop the registers, and return.
Z-80 Fixed Point Addition
SUM: .BLKB 258 (for max of 255 byte number and 3 byte descriptor block)
ENDSUMr.BLKB 1
BLOCKA: 3 (storage area for descriptor blocks of input)
BLOCKS: 3
FXPTAD: PUSH AF Save registers
PUSH BC
PUSH DE
PUSH HL
LD DE,BLXKA Pointer to block save area
LD HL, VARA Pointer to descriptive block
LD BC,3 Number of bytes in block
LOIR Transfer block to block save area
LD BC,3 Bytes in second block
LD HL,VARB Pointer to second descriptive block (DE already points
to second save area)
LDIR Transfer second block to save area
LD A,(SZMAX) Fetch maximum size
LD C,A Save
(ALIGN DECIMAL POINT)
LD A, (VARB+1) Number of decimal places in VARB
LD B,A Save
LD A,(VARA+1) Number of decimal places in VARA
SUB B Find the difference
LD D,A Save
JR Z,FXPT20 Jump if same number of places
JP NC,FXPT15 Jump if A has more
LD H,VARA Pointer to size of VARA
FXPT05: ADD A,(HL) Get new size
CP C C^pare to maximum size
JR Z,FXPT10 If same, we're OK
CALL NC,OVFLOW If over max, call overflow
FXPT10: LD (HL),A Store new size
LD A,D Restore difference
INC HL Pointer to decimal places in variable
ADD A,(HL) New decimal places
LD (HL),A Store new decimal places
161
LD (SUNH-1),.A Store decimal places in sum
JP FXPT20 Jump
FXPT15: LD HL,VARB Pointer to size of VARB
JP FXPT05 Get new size
(CHECK SIGN OF NUMBERS)
FXPT20: LD A,(VARB+2) Sign of VARB
LD B,A Save
LD A,(VARA+2) Sign of VARA
CP B Do sings match?
JR NZ,FXPT25 No, jump
LD (SUM+2),A Give their common sign to the result
LD HL, VARA Pass the parameters to BCD ADD
LD (ADD11,HL
LD HL,VARA
LD (ADD2),HL
LD HL,SUM
LD (RESULT), HL
CALL BCDADD Add the two numbers
JP FXPT45
FXPT25: LD A, (VARB) Size of VARB
LD B,A Save
LD A, (VARA) Size of VARA
CP B Are numbers the same size?
JR NZ,FXPT35 No, jump
LD DE,VARA+3 First byte of number of VARA
LD HL,VARB+3 First byte of number of VARB
FXPT30: LD A,(DE) Fetch byte of VARA
CP (HL) Compare to VARB, same?
JR NZ,FXPT35 No, jump
INC DE Yes, then check next byte
INC HL
DJNZ FXPT30
SUB A The two numbers are equal, so move zero to sum
LD (SUM), A
LD (SUM+1),A
LD (SUMf2),A
JR FXPT45
FXPT35: JP C,FXPT40 Jump if VARB is larger
LD A,(VARA+2)
LD (SUM+2),A
LD HL,VARA Prepare parameters to subtract VARB from VARA
LD (MNUEND),HL
LD HL.VARA
162
FXPT40:
FXPT45:
LD
(SBTRHD),HL
LD
HL,SUM
LD
(DFFRNC),HL
CALL
BCDSUB
JR
FXPT45
LD
A,(VARB+2)
LD
(SUM+2) ,A
LD
HL,VARB
LD
(MNUEND) ,HL
LD
HL,VARA
1 n
^QRTDI-in^ l-ll
\ OD 1 KnU ^ ) rIL
LD
HL,SUM
LD
(DFFRNC),HL
CALL
BCDSUB
Subtract
Prepare parameters to subtract VARA from VARB
The routine is essentially complete. Just move the
descriptive blocks back from the save area, pop the
registers, and return.
The two routines BCDADD and BCDSUB are extremely simple. They are just
multibyte addition and subtraction with decimal adjust between each add
or subtract. BCDSUB should squeeze out any leading 00 bytes before returning.
3) The fixed point subtract is trivial once the fixed point add has been
written. The algorithm follows:
a) load and save the sign of the subtrahend
b) reverse the sign in the descriptor block
c ) ca I I FXPTAD
d) replace the original sign
4) A portion of the floating point multiply subroutine will be given here.
What will not be shown is:
a) initially saving the registers and the descriptor blocks of
MLTPLR and MLTCND and clearing PRODCT.
b) adding the two numbers of digits to the right of the decimal
point and storing it in the descriptor block of the result
c) determining which number is longer. Placing a pointer to the
end of the shorter in the HL register pair placing the size of
the shorter in the C register
d) determining the sign of the result and storing it
e) restoring registers and descriptor blocks
What will be shown is performing the mul tipl icatlon itself using calls
to BCDADD.
163
8080 Floating Point Multiply
rrMUL 1 :
•
•
•
XCHG
Swap DE and HL
LXI
H,MLTCND
Set up parameters for BCDADD
SHLD
ADDl
LXI
H,PRODCT
SHLD
ADD2
SHLD
RESULT
i.e., ADD2-«-ADDl + ADD2
XCHG
Swap back
BIGLP:
MOV
A,M
Fetch byte of multiplier
ANI
0FH
Clear high order digit
JZ
LILP2A
MOV
B,A
Save as counter
LILPl:
CALL
BCDADD
Add multiplicand a single time
DCR
B
Decrement counter
JNZ
LILPl
Repeat addition the number of times of the digit
LILP2A:
CALL
LFTSFT
Shift number 4 bits to left for multiply by 10
MOV
A,M
Get byte again
ANI
JZ
RRC
0F0H
LILP4
Clear low order digit
Rotate four times
RRC
RRC
RRC
MOV
B,A
Save as counter
LI LPS:
CALL
BCDADD
Add multiplicand a single time
XR
B
Decrement counter
JNZ
LILP2
Repeat addition the number of times of the digit
LILP4:
CALL
RGTSFT
1_ • ^ 1 11 i_ iii»i__t__i_l •! 1 / • i_ 1
Shifts the number 4 bits to the right (i.e., back
to original alignment) and adds a 00 byte to the
end. This accomplishes a second 4 bit shift to
the left without having the number move through
memory by more than one byte.
DCX
H
[iexf byte of multiplier
DOR
C
Decrement byte count
JNZ
•
•
•
BIGLP
Repeat unti 1 done
Z-80
Floating Point
Mu 1 1 i p 1 y
FPMULT:
•
•
•
SUB
A
Clear accumulator
164
LD
HL,MLTCND
Set up parameters for BCDADD
LD
(ADD1),HL
LD
HL,PRODCT
LD
(ADD2),HL
LD
(RESULT), HL
i.e., ADD2^ADD2 + ADDl
BIGLP:
RRD
Fetch first digit
LD
B,A
Save as counter
LILPl:
CALL
BCDADD
Add multipl icand
DJNZ
LILPl
Repeat the number of times of the digit
CALL
LFTSFT
Shift number 4 bits 1o left for multiply by 10
RRD
Fetch second digit
LD
B,A
Save as counter
LILP2:
CALL
BCDADD
Add mu 1 1 i p 1 i cand
DJNZ
LILP2
Repeat the number of times of the digit
CALL
RGTSFT
Shifts the number 4 bits to the right (i.e., back
to original alignment) and adds a 00 byte to the
end. This accomplishes a second 4 bit shift to
ine leiT wiinouT naving tug numuer move inrougn
memory by more than one byte
INC
HL
Next byte of multiplier
DEC
C
Decrement byte count
JR
•
•
NZ, BIGLP
Repeat unti 1 done
5) Floating point division will again make use of LFTSFT and RGTSFT to
prevent the dividend from wandering through memory. It will also save
and later restore the descriptor blocks of the dividend and divisor.
It will have to call the fixed point subtract subroutine rather than
BCDSUB, because the sign of the result is not known beforehand.
165
index
Accumulator, 14, 31
ACT, 32, 106
ADC, 32, 41, 106, 108
ADD, 32, 40, 41, 106, 108
Addition, 8, 9, 32, 40, 41
Address, 15, 17
ADI, 32, 106
ANA, 34, 107
AND, 11, 33, 34, 107
ANI. 34, 107
Arithmetic, 31
Array, 72, 80
ASCII, 68, 113
Available nodes, 78
Binary, 4-6
Binary coded decimal, 83
Bit. 7
BIT, 58, 109
Bit manipulation, 57
Block search, 79
Block transfer, 79
Body, 44
Boolean, 10
Borrow, 9
Boundary alignment, 76
Byte, 7
CALL, 52, 53, 110, 111
Carry flag, 9, 10, 12
CC, 53, 110
CCD, 80, 106
CCDR, 80, 106
CCF, 39, 107
CCI. 80, 106
CCIR, 80. 106
Clock speed, 101
CM, 53, 1 1 1
CM A, 39. 107
CMC, 39. 107
CMP, 37, 107
CNC, 53, 111
CNO, 53, 111
CNZ. 53. 110
CO. 53, 111
Compare, 34
Complement accumulator, 38
Complement carry, 39
Conditional jump, 44
Con\ersions, 5
CP, 37. 53, 107, 111
CPD, 80, 106
CPDR, 80, 106
CPE, 53, 111
CPI, 37. 80. 106, 107
CPIR, 80, 106
CPL. 39. 107
CPO, 53, 111
CZ, 53, 1 1 1
DAA, 85, 107
DAD, 40, 108
DADC, 41, 108
DADX, 41, 108
DADY, 41, 108
DCR, 38, 107
DCX. 40, 108
DEC, 38, 40, 107, 108
Decimal, 5. 6
Decimal adjust, 84
Declaration, 71
Decrement, 37
DI, 107
Digits, 4, 6
Displacement, 21, 75
Division, 62
DJNZ. 50, 110
Documentation. 98
DSBC, 41, 108
166
Index
EI, 107
LDDR, 79, 106
Fouate 74
LDED '^4 104
X~^ X^ y X J 1 V/ X
EX 27 28 105 106
LDI 79 106
EXAF 28 105
LDIR 79 106
X^ X XX J § mj y A \/ \J
Exchanjie 26
LHLD, 24, 104
Exclusive OR 1*^ 83
I inkpH striirt iirp^ 77
X~<I I 1 ^ V. vX 0LiUv.LL11^0) / 1
EXX '^8 105
LIXD ''4 104
^ ■ X ^ X X^ t ^ I y X \J X
LIYD, 24, 105
Flags 31 32
LSPD 24 105
X iKj X X_^ J X J A \y «^
LXI 24 104
Hexadecimal, 4—6
Load 17 22
I offiral 3 1
IM, 108
Loop, 44, 50
Immediate 20 24
IN, 111
Magnitude bits, 7, 10
IXC 38 40 107 108
\femorv 1 5
Inrrement 37 44 4'i
\rpmorv-reffister 18 22
IND, 112
^Mnemonics 17
A * A A ft A ft A V-/ ft ft ft ^^4^ y ft f
Index register 21
^fofliilnr Droeramminir 51 52
i ■ ft V/ V ft V« 1 t-ft ■ L.^ ft \J ft U ftftliftftftft ft ft >^ t V-^ ft f \J ^
INDR. 1 12
\fonitor 6Q
INI. 1 12
MOV 104
INIR. 112
^riilti-dimensional arrav. 72
A * 1 LX li,l \.ftllll\.ftft>Jl \J 1 ft U X U ft ft U T y f
Initialization, 44
Multiplication, 60
INP, 1 1 1
MVI 104
A * X T X y X V/ X
INR 38 107
INX 40 108
NEC 39 107
1, ^ X^ X^ « ^ < 1 V 1
Neeate 39
TC 47 110
Nibble 7
TM 47 110
NOP 40 107
ft ^ X f X ^/ y ft #
IMP 47 109
NOT 38
TMPR 49 110
Number svstein 4
1^ UlllL^^l ij T (J V> IIX f X
INC 47 110
T\0 47 110
One's romnlement 8
V 1 I \_ .} \j 111 AV-iiiv. ftft y
TNZ 47 110
OR 11 33 107
v^ft.^f ft ftf \^ %^ f ft 9
TO 47 110
OR A 34 107
V ^ XX.i Xf %J A y M \J t
TP 47 109 110
IXf Iff IV^v^j liV/
ORI 34 107
TPE. 1 10
OTDR. 1 12
JPO. 1 10
OTIR. 1 12
TR 49 110
OUT. 1 12
TRC 49 110
1 XX , I mJ ^ 11 \J
OITTD 112
V ^ X X y ^ 11^
TRNC 49 110
OITTDR 112
X^ V X A,j^ X X « ft 1 ^
TRNZ 49 110
1 XX A ^ X^ f 1 f 11 \J
OUTI, 112
TRZ 49 110
1 1 X X^ 1 1 • 11 V/
OrTIR, 112
TZ 47 109
Ol'TP. 112
Overflow flae 9 10
I RC D 104
I D 17-''l ''3 '>A 104 IOt
Paee 76
LDA ''0 104
Parity flair P
M 11 ftft f-^ 1 1
LDAI. 104
Patch. 100
LD.AR. 104
PCHL. .50. 110
LD.AX. 19, 104
PCIX. 51, 110
LDD, 79, 106
PCIY, 51, 110
168
Z-89 and 8989 Assembly Language Programming
POP, 25, 26, 111
SHLD, 24, 105
Post-test, 45
Sign, 12
Pre-test, 45
Sign bit, 7, 10
Program counter, 15, 16, 22, 43
Signed compare, 35, 36
PUSH, 25, 26, 105
SIXD, 24, 105
SIYD, 24, 105
RAL, 59, 108
SLA, 67, 109
RALR, 66, 109
SLAR. 67, 109
RAR, 59, 108
SPHL, 23, 105
RARR, 66, 109
SPIX, 23, 105
RC, 54, 111
SPIY, 23, 105
Register, 14
SRA. 67, 109
Register indirect jump, 50
SRAR, 67, 109
Register pair, 15
SRL, 67. 109
Relative jump, 47, 48
SRLR, 67, 109
RES, 58, 109
SSPD, 24. 105
RET, 54. Ill
ST A. 20. 104
RETI. Ill
Stack. 16
RETN, 111
Stack pointer, 15, 22, 25
RL. 66. 109
STAI. 104
RLA. 59. 108
STAR. 104
RLC. 59. 66. 108
ST AX. 104
RLCA, 59. 108
STC, 107
RLCR. 66. 108
Structure, 73
RLD. 68. 109
Structured programming, 52
RM. 54. Ill
SUB, 33, 106, 107
RNC. 54. Ill
Subroutine, 51, 52
RNO. 54, 111
Subtraction. 9, 33, 40, 41
RNZ. 54. Ill
SUI, 33. 107
RO. 54, 111
Swapped format, 23
Rotate, 59, 66, 68
RP. 54. Ill
T-state, 101
RPE, 54, 111
Test, 45, 46
RPO, 54, 111
Top down, 98
RR. 66. 109
Two's complement, 7
RRA. 59. 108
RRC. 59. 66, 108. 109
Unsigned compare, 37
RRCA. o9, 108
Utility, 69
RRCR, 66. 109
RRD, 68. 109
Value, 17
RST. Ill
RZ, 54, 111
Variable, 14, 71, 75
SBB, 33, 107
XCHG, 27, 105
SBC, 33, 41, 107, 108
XRA, 34, 107
SBCD. 24, 105
XRI, 34, 107
SBI, 33, 107
XOR, 12, 33, 107
SCF, 39, 107
XTHL, 27, 106
SDED, 24, 105
XTIX, 27, 106
SET, 58, 109
XTIY, 27, 106
Set carry, 39
Shift, 59, 66. 67
Zero flag, 12
HOBBY WORLD
N2 6113
Date
19511 Business Center Drive
Northridge, Ca. 91324
CALL TOLL FREE: (800)-423-5387
CA, HI, AK: (213) 886-9200
Name
Address
City/State/Zip
Phone
Sold by
COD
Cash
Check
Chg.
Acct.
New
Code
J
Source
Qty
Cat. No.
Description
Unit Price
Total
v
el
Ship Via Tax
Shipping
TOTAL
C,
All returns must be accompanied by this receipt.
5167-0
$7.95 Z-80 AND 8080 ASSEMBLY LANGUAGE
PROGRAMMING
Kathe Spracklen
Here is the first book that gives you an introductory look at
assembly language programming for the Z-80 and 8080 pro-
cessors. It is intended to provide just about everything the
applications programmer needs to know to get the most out
of his or her machine. Programming techniques are presented
along with the instructions. Numerous diagrams and examples
are provided. Exercises, with answers, are included with each
chapter, making it ideal for self-study and for schools.
Other Books of Interest . . .
SARGON: A Computer Chess Program
Dan and Kathe Spracklen
This is the computer chess program that won first prize in the
chess tournament at the 1978 West Coast Computer Faire.
Available in book form (#5155-7, paper, 120 pages) or on
computer program tapes for the TRS-80 Level II (#00603) and
Apple II-24K (#00604) machines.
BASIC BASIC: An Introduction to Computer
Programming in BASIC Language, Second Edition
and
ADVANCED BASIC: Applications and Problems
Both by James S. Coan
Two books that give you the complete picture of the BASIC
language. One introduces the language; the other offers ad-
vanced techniques and applications. Basic BASIC, #5106-9,
paper, #5107-7, cloth, 288 pages; Advanced BASIC, #5855-1,
paper, #5856-X, cloth, 192 pages
BASIC MICROPROCESSORS AND THE 6800
Ron Bishop
Two valuable books in one: an introduction to microproces-
sors for the beginner, and a complete description of the M6800
system for the engineer. #0758-2, paper, 272 pages
THE 6800 MICROPROCESSOR: A Self-Study Course
with Applications
Lance A. Leventhal
A simple introduction to the 6800 microprocessor, including
15 laboratory exercises that emphasize the control applica-
tions of microcomputers. #5120-4, paper, 112 pages
HAYDEN BOOK COMPANY, INC.
Rochelle Park, New Jersey
ISBN 0-81 04-61 67-0